Index: /gssim_ui/branches/vine/gssimstudio/ant/project.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/ant/project.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/ant/project.properties	(revision 15)
@@ -0,0 +1,11 @@
+#----------------------------------------------------------
+# Project information settings
+#----------------------------------------------------------
+#Mon, 06 Sep 2010 10:08:38 +0200
+
+project.name=gssimstudio
+project.title=GSSIM Studio 
+project.description=This is GSSIM Studio portlet app.
+project.priority=9
+project.extends=grid,group,grms3client
+project.uses=
Index: /gssim_ui/branches/vine/gssimstudio/.project
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/.project	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/.project	(revision 15)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>gssimstudio_vine</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+	</buildSpec>
+	<natures>
+	</natures>
+</projectDescription>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ArchiveViewer.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ArchiveViewer.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ArchiveViewer.properties	(revision 15)
@@ -0,0 +1,21 @@
+# locale/pl_PL/ArchiveViewer.properties
+Name=Nazwa
+Comment=Komentarz
+Save=Zapisz
+Delete=UsuÅ
+View=PrzeglÄ
+daj
+Move=PrzenieÅ
+
+CommissionDate=Zlecono
+Status=Status
+Refresh=OdÅwieÅŒ
+
+Basic=Informacje podstawowe
+Resource=Wykres zasobÃ³w
+Task=Wykres zadaÅ (Gannt)
+Line=Wykres liniowy
+Other=Inne
+
+Details=szczegÃ³Åy
+Configuration=Konfiguracja
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/TopologyEditor.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/TopologyEditor.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/TopologyEditor.properties	(revision 15)
@@ -0,0 +1,63 @@
+# locale/pl_PL/TopologyEditor.properties
+EditMode=Tryb edycji
+ViewMode=Tryb przeglÄ
+dania
+Toolbox=NarzÄdzia
+NormalMode=Tryb swobodny
+PropertiesMode=Tryb informacyjny
+LinkMode=Tryb ÅÄ
+czenia
+RemoveMode=Tryb usuwania
+AddNew=Dodaj nowy
+User=Obiekt UÅŒytkownika
+Resource=ZasÃ³b
+Router=Router
+Layout=ukÅad
+Simple=Prosty
+ForceDirected=Fizyczny
+Radial=Promienisty
+TreeIndent=Drzewiasty
+ZoomIn=PrzybliÅŒ
+ZoomOut=Oddal
+Minimap=Minimapa
+Name=Nazwa
+SaveClose=Zapisz i zamknij
+InvalidDataInField=NiektÃ³re pola posiadajÄ
+ niepoprawne wartoÅci.
+BaudRate=PrÄdkoÅÄ ÅÄ
+cza
+PropagationDelay=OpÃ³Åºnienie
+Workload=ObciÄ
+ÅŒenie
+MTU=MTU
+Processors=Procesory
+Resources=Zasoby
+Tasks=Zadania
+TasksWaitingTime=Czasy oczekiwaÅ zadaÅ
+Reservations=Rezerwacje
+EnergyUsage=ZuÅŒycie energii
+Diagrams=Wykresy
+Menu=Menu
+MenuTooltip=OtwÃ³rz menu
+New=Nowy
+NewTooltip=UtwÃ³rz nowÄ
+ sieÄ
+Open=OtwÃ³rz
+OpenTooltip=OtwÃ³rz sieÄ z pliku
+Save=Pobierz
+SaveTooltip=Pobierz w postaci pliku
+SaveServer=Zapisz
+SaveServerTooltip=Zapisz jako plik na serwerze
+Tools=NarzÄdzia
+Map=Mapa
+Close=Zamknij
+CloseTooltip=Zamknij menu
+ResourcesSubmenu=Zasoby >
+NetworkSubmenu=Topologia >
+Cluster=Klaster
+Count=IloÅÄ
+PNGFile=Jako PNG
+PNGFileTooltip=Zapisz aktualny widok do pliku PNG
+
+filenamePromptText=Nazwa pliku
+filenamePromptTitle=Zapisywanie jako
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Charts.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Charts.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Charts.properties	(revision 15)
@@ -0,0 +1,33 @@
+# locale/pl_PL/Charts.properties
+ResourceAllocationTitle=Wykres zuÅŒycia zasobÃ³w dla Grid Scheduling Simulator
+ResourceEnergyTitle=Wykres zuÅŒycia energii dla Grid Scheduling Simulator
+CreatedFor=utworzony dla
+Created=utworzony
+Day=dnia
+Clone=Kopiuj
+CPU=Liczba wykorzystanych procesorÃ³w
+SimulationTime=Czas symulacji
+ComparisonTitle=Wykres porÃ³wnawczy eksperymentÃ³w dla Grid Scheduling Simulator
+IncludedExperiments=Eksperymenty na wykresie:
+AvailableExperiments=DostÄpne eksperymenty:
+Experiment=Eksperyment
+Plot=Rysuj!
+Collapse=ZwiÅ
+UnCollapse=RozwiÅ
+ColumnType=Kolumnowy
+LinearType=Liniowy
+ExperimentType=Eksperyment
+ParameterType=Metryka
+AllocationType=Alokacja
+EnergyType=Energia
+XAxisParameterLabel=OdÅÃ³ÅŒ na osi X
+ChartTypeLabel=Typ wykresu
+CharacteristicType=Charakterystyka
+MeanType=Årednia
+StdevType=Odch.std.
+VarType=Wariancja
+MinType=Minimum
+MaxType=Maximum
+CountType=Liczba
+SumType=Suma
+Aggregate=Sumaryczny
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ExperimentEditor.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ExperimentEditor.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ExperimentEditor.properties	(revision 15)
@@ -0,0 +1,145 @@
+# locale/pl_PL/TopologyEditor.properties
+Plugins=Pluginy
+Statistics=Statystyki
+Files=Pliki
+PickOne=(wybierz...)
+Import=Importuj...
+Save=Zapisz
+Show=PokaÅŒ
+
+Workspace=ZbiÃ³r roboczy
+
+#AccumulatedResources=Accumulated resources
+#AccumulatedResourcesTooltip=Specifies whether accumulated resources statistics should be created.
+#ExtendedTasks=Extended tasks
+#ExtendedTasksTooltip=Specifies whether extended tasks statistics should be created.
+#GridletHistory=Gridlet history
+#GridletHistoryTooltip=Specifies whether history of gridlets should be created.
+#Jobs=Jobs
+#JobsTooltip=Specifies whether jobs (accumulated task) statistics should be created.
+#Simulation=Simulation
+#SimulationTooltip=Specifies whether accumulated simulation statistics should be created.
+
+#GridScheduling=Grid scheduling
+#GridSchedulingTooltip=Specifies which plugin is used to manage broker interface.
+#LocalGrid=Local grid
+#LocalGridTooltip=Specifies which plugin is used to manage local policies.
+#ExecutionTimeEstimation=Execution time estimation
+#ExecutionTimeEstimationTooltip=Specifies which plugin is used to estimate task execution time.
+
+NetworkTopology=Topologia sieci
+NetworkTopologyTooltip=Plik opisujÄ
+cy topologiÄ sieci.
+Workload=Workload
+WorkloadTooltip=Plik definiujÄ
+Â
+cy zadania (workload).
+ResourceDescription=Opis zasobÃ³w
+ResourceDescriptionTooltip=Plik definiujÄ
+cy zasoby.
+
+FromNetworkEditor=Z edytora sieci
+FromNetworkEditorDescription=Aktualny plik z edytora sieci.
+FromWorkloadEditor=Z edytora workloadu
+FromWorkloadEditorDescription=Aktualny plik z edytora workloadu.
+
+#fields describing workload file columns
+Field1=Numer zadania
+Field2=Czas zgÅoszenia
+Field3=Czas oczekiwania
+Field4=Czas pracy
+Field5=Liczba zaalokowanych CPU
+Field6=Årednie zuÅŒycie czasu CPU
+Field7=Wykorzystana pamiÄÄ
+Field8=Å»Ä
+dana liczba CPU
+Field9=Å»Ä
+dana iloÅÄ czasu CPU
+Field10=Å»Ä
+dana iloÅÄ pamiÄci
+Field11=Status
+Field12=ID uÅŒytkownika
+Field13=ID grupy
+Field14=Numer aplikacji
+Field15=Numer kolejki
+Field16=Numer partycji
+Field17=Numer poprzedzajÄ
+cego zadania
+Field18=Czas oczekiwania po poprzedzajÄ
+cym zadaniu
+
+WorkloadData=Dane
+Header=NagÅÃ³wki
+Statistics=Statystyki
+
+Name=Nazwa
+Value=WartoÅÄ
+
+GraphNotConnectedError=Graf nie jest spÃ³jny. Upewnij siÄ, ÅŒe wszystkie wierzchoÅki sÄ
+ odpowiednio poÅÄ
+czone.
+WorkloadNotGeneratedError=Workload nie zostaÅ wygenerowany. PrzejdÅº do edytora workloadu i wygeneruj go.
+InvalidExperimentPropertiesError=NiektÃ³re parametry eksperymentu nie sÄ
+ prawidÅowe, wprowadÅº odpowiednie zmiany.
+
+JobCount=Liczba zadaÅ
+LongestRun=NajdÅuÅŒszy czas pracy (czas oczekiwania + czas pracy)
+AvgRunTime=Åredni czas pracy
+MaxReqMem=NajwiÄksze ÅŒÄ
+danie przydziaÅu pamiÄci [kb na procesor]
+MaxReqTime=NajwiÄkszy ÅŒÄ
+dany czas pracy [sekundy]
+
+RunButton=ZleÄ zadanie
+RunButtonTooltip=Uruchom symulacjÄ GSSim przez zlecenie zadania via GRMS
+SendButton=Zapisz eksperyment
+SendButtonTooltip=Zapisz aktualnÄ
+ konfiguracjÄ eksperymentu na zdalnym serwerze
+
+ShowDebugButton=WÅÄ
+cz/wyÅÄ
+cz elementy DEBUG
+ShowDebugButtonTooltip=Pokazuje lub ukrywa elementy GUI z dodatkowymi informacjami
+
+DataOverrideAlert=Dane w edytorze topologii zostanÄ
+ nadpisane - czy na pewno kontynuowaÄ?
+DataOverrideAlertTitle=Uwaga
+
+CreateNewExperiment=StwÃ³rz nowy eksperyment
+New=Nowy
+AddFile=Dodaj plik
+ClearFiles=UsuÅ wszystkie pliki ze zbioru roboczego
+Metaname=Grupa eksperymentÃ³w
+Add=Dodaj
+AddTooltip=Dodaj nowy eksperyment dla tych ustawieÅ i zamknij to okno
+Clone=Klonuj
+CloneTooltip=Dodaj nowy eksperyment dla tych ustawieÅ i nie zamykaj tego okna
+Cancel=Anuluj
+CancelTooltip=Zamknij to okno
+Runs=Liczba symulacji
+Actions=Akcje
+Load=L
+LoadTooltip=Wczytaj plik
+Remove=-
+RemoveTooltip=UsuÅ plik
+Edit=Edytuj
+EditTooltip=ZmieÅ wÅaÅciwoÅci tego elementu
+Perform=Wykonaj
+PerformTooltip=Wykonaj eksperyment na symulatorze
+PerformAll=Wykonaj wszystkie
+PerformAllTooltip=Wykonaj wszystkie eksperymenty na symulatorze
+Upload=PrzeÅlij
+Clear=WyczyÅÄ
+About=Opis
+
+UseSelectedFiles=UÅŒyj wszystkich plikÃ³w
+
+GlobalPlugin=Plugin globalnego zarzÄ
+dcy
+LocalPlugin=Plugin lokalnego zarzÄ
+dcy
+ExecutionPlugin=Plugin estymacji czasu wykonania
+
+FileManager=ZarzÄ
+dzaj plikami
+Close=Zamknij
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Common.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Common.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Common.properties	(revision 15)
@@ -0,0 +1,7 @@
+# locale/pl_PL/Common.properties
+ExperimentEditor=Edytor Eksperymentu
+TopologyEditor=Edytor Topologii Sieci
+WorkloadGeneratorEditor=Edytor Generatora Workloadu
+ArchiveViewer=Archiwum eksperymentÃ³w
+English=English
+Polish=Polski
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Help.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Help.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/Help.properties	(revision 15)
@@ -0,0 +1,7 @@
+# locale/pl_PL/Common.properties
+ExperimentEditor=Edytor Eksperymentu
+TopologyEditor=Edytor Topologii Sieci
+WorkloadGeneratorEditor=Edytor Generatora Workloadu
+ArchiveViewer=Archiwum eksperymentÃ³w
+English=English
+Polish=Polski
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/WorkloadEditor.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/WorkloadEditor.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/WorkloadEditor.properties	(revision 15)
@@ -0,0 +1,86 @@
+# locale/pl_PL/WorkloadEditor.properties
+Validate=Waliduj drzewo
+Preferences=Preferencje
+AddNewPreference=Dodaj nowe preferencje
+ComputingResourceHostParameters=Parametry hostÃ³w zasobÃ³w obliczeniowych
+AddNewComputingResourceHostParameter=Dodaj nowy parametr hosta
+Edit=Edytuj
+Clear=UsuÅ
+#SimulationStartTime=Data rozpoczÄcia symulacji
+#JobCount=IloÅÄ grup zadaÅ
+#SimulationTime=Czas symulacji
+#TaskCount=
+#TaskLength=
+#JobPackageLength=
+#JobInterval=
+#ExecDuration=
+#PeriodStart=
+#PeriodEnd=
+#PeriodDuration=
+Buttons=Przyciski
+Metric=Metryka
+Type=Typ
+Basic=Podstawowe
+Dependencies=ZaleÅŒnoÅci
+TreeView=Widok drzewa
+Menu=Menu
+MenuTooltip=OtwÃ³rz menu
+New=Nowy
+NewTooltip=StwÃ³rz nowy Workload
+Open=OtwÃ³rz
+OpenTooltip=OtwÃ³rz Workload z pliku...
+Save=Zapisz
+SaveTooltip=Zapisz Workload do pliku...
+InvalidWorkloadError=WystÄ
+piÅ bÅÄ
+d, sprawdÅº listÄ bÅÄdÃ³w w celu rozwiÄ
+zania problemÃ³w.
+Value=WartoÅÄ
+Minimum=Minimum
+Maximum=Maksimum
+Close=Zamknij
+AddNewDist=Dodaj nowy rozkÅad
+ID=Id
+ReferenceID=ZaleÅŒy od Id
+Expression=WyraÅŒenie
+Average=Årednia
+StandardDeviation=Odchylenie standardowe
+RandomSeed=Ziarno
+Distribution=Typ rozkÅadu
+Attributes=Atrybuty
+PeriodicValidValuesDates=Okresowo waÅŒne wartoÅci
+BeginDate=Data poczÄ
+tku
+EndDate=Data zakoÅczenia
+Name=Nazwa
+#Endpoint=
+#Importance=
+OptimizationType=Typ optymizacji
+PreferenceType=Typ preferencji
+AddNewPreferenceParameter=Dodaj nowe parametry preferencji
+BeginTime=Czas rozpoczÄcia
+EndTime=Czas zakoÅczenia
+AddNewPeriod=Dodaj nowy okres
+#MultiDistribution=
+Show=PokaÅŒ
+ShowTooltip=PokaÅŒ widok drzewa
+Generate=Generuj
+GenerateTooltip=Generuj na podstawie zdefiniowanych parametrÃ³w.
+UnknownError=WystÄ
+piÅ nieznanny bÅÄ
+d.
+MissingPreferenceTypeError=Brakuje okreÅlonego typu referencji.
+MissingNameError=Brakuje nazwa.
+MissingImportanceError=Brakuje importance.
+MissingOptimizationTypeError=Brakuje typu optymizacji.
+MissingValueError=Brakuje wartoÅci.
+CannotBeSetTogetherError=- nie mogÄ
+ byÄ ustawione obydwa.
+UnknownReferenceError=Referencja do nieznanego ID.
+SelfReferenceError=Referencja na siebie samego.
+DoubleIDError=Element o podanym ID juÅŒ istnieje.
+MissingError=Brak.
+OneMustBeSetError=- jeden z tych elementÃ³w musi zostaÄ zdefiniowany.
+Remove=UsuÅ
+ProbabilisticParameters=Parametry probabilistyczne
+Dates=Daty
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/gssimstudio.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/gssimstudio.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/gssimstudio.properties	(revision 15)
@@ -0,0 +1,3 @@
+#Mon, 06 Sep 2010 10:08:38 +0200
+
+testKey=test value for locale pl_PL
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ResourceEditor.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ResourceEditor.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/pl_PL/ResourceEditor.properties	(revision 15)
@@ -0,0 +1,20 @@
+# locale/pl_PL/Common.properties
+AddNewResource=Dodaj nowy zasÃ³b
+PropertyType=Typ wÅasnoÅci
+AddNewProperty=Dodaj nowÄ
+ wÅasnoÅÄ
+ParameterType=Typ parametru
+AddNewHostParameter=Dodaj parametr hosta
+HostParameterType=Typ parametru hosta
+Property=WÅasnoÅÄ
+Parameter=Parametr
+HostParameter=Parametr hosta
+ComputingResource=ZasÃ³b obliczeniowy
+ResourceId=ID zasobu
+AddNewOtherParameter=Dodaj pozostaÅe parametry
+OtherParameter=PozostaÅe parametry
+OtherParameterType=Typ pozostaÅych parametrÃ³w
+AddNewQueueParameter=Dodaj parametr kolejki
+EditQueue=Edytuj kolejkÄ
+EditResource=Edytuj zasÃ³b
+QueueParameter=Parametr kolejki
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ResourceEditor.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ResourceEditor.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ResourceEditor.properties	(revision 15)
@@ -0,0 +1,19 @@
+# locale/en_US/Common.properties
+AddNewResource=Add new resource
+PropertyType=Property type
+AddNewProperty=Add new property
+ParameterType=Parameter type
+AddNewHostParameter=Add new host parameter
+HostParameterType=Host parameter type
+Property=Property
+Parameter=Parameter
+HostParameter=Host parameter
+ComputingResource=Computing resource
+ResourceId=Resource Id
+AddNewOtherParameter=Add new other parameter
+OtherParameter=Other parameter
+OtherParameterType=Other parameter type
+AddNewQueueParameter=Add new queue parameter
+EditQueue=Edit queue
+EditResource=Edit resource
+QueueParameter=Queue parameter
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ArchiveViewer.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ArchiveViewer.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ArchiveViewer.properties	(revision 15)
@@ -0,0 +1,20 @@
+# locale/en_US/ArchiveViewer.properties
+Name=Name
+Comment=Comment
+Save=Save
+Delete=Delete
+View=View
+Move=Move
+
+CommissionDate=Submitted
+Status=Status
+Refresh=Refresh
+
+Basic=Basic info
+Resource=Resource chart
+Task=Gannt chart
+Line=Line chart
+Other=Other
+
+Details=details
+Configuration=Configuration
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/TopologyEditor.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/TopologyEditor.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/TopologyEditor.properties	(revision 15)
@@ -0,0 +1,57 @@
+# locale/en_US/TopologyEditor.properties
+EditMode=Edit mode
+ViewMode=View mode
+Toolbox=Toolbox
+NormalMode=Normal mode
+PropertiesMode=Properties mode
+LinkMode=Linking mode
+RemoveMode=Remove mode
+AddNew=Add new
+User=User
+Resource=Resource
+Router=Router
+Layout=Layout
+Simple=Simple
+ForceDirected=Force directed
+Radial=Radial
+TreeIndent=Tree indent
+ZoomIn=Zoom in
+ZoomOut=Zoom out
+Minimap=Minimap
+Name=Name
+SaveClose=Save & Close
+InvalidDataInField=Some fields have invalid data.
+BaudRate=Baud rate
+PropagationDelay=Propagation delay
+Workload=Workload
+MTU=MTU
+Processors=Processors
+Resources=Resources
+Tasks=Tasks
+TasksWaitingTime=Tasks waiting time
+Reservations=Reservations
+EnergyUsage=Energy usage
+Diagrams=Diagrams
+Menu=Menu
+MenuTooltip=Open menu
+New=New
+NewTooltip=Create new network
+Open=Open
+OpenTooltip=Open network from file
+Save=Download
+SaveTooltip=Download as file
+SaveServer=Save
+SaveServerTooltip=Save file on server
+Tools=Tools
+Map=Map
+Close=Close
+CloseTooltip=Close this menu
+ResourcesSubmenu=Resources >
+NetworkSubmenu=Network >
+Cluster=Cluster
+Count=Count
+PNGFile=To PNG
+PNGFileTooltip=Save current view as PNG file
+
+filenamePromptText=Filename
+filenamePromptTitle=Save as
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Charts.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Charts.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Charts.properties	(revision 15)
@@ -0,0 +1,33 @@
+# locale/en_US/Charts.properties
+ResourceAllocationTitle=Resource Utilization Chart for Grid Scheduling Simulator
+ResourceEnergyTitle=Resource Energy Usage Chart for Grid Scheduling Simulator
+CreatedFor=created for
+Created=created
+Day=at
+Clone=Clone
+CPU=Number of CPU's used
+SimulationTime=Simulation time
+ComparisonTitle=Experiment Comparison Chart for Grid Scheduling Simulator
+IncludedExperiments=Included experiments:
+AvailableExperiments=Available experiments:
+Experiment=Experiment
+Plot=Plot!
+Collapse=Collapse
+UnCollapse=Show
+ColumnType=Column
+LinearType=Linear
+ExperimentType=Experiment
+ParameterType=Metric
+AllocationType=Allocation
+EnergyType=Energy
+XAxisParameterLabel=Plot as X axis
+ChartTypeLabel=Chart type
+CharacteristicType=Characteristic
+MeanType=Mean
+StdevType=St.dev.
+VarType=Variance
+MinType=Minimum
+MaxType=Maximum
+CountType=Count
+SumType=Sum
+Aggregate=Aggregated
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ExperimentEditor.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ExperimentEditor.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/ExperimentEditor.properties	(revision 15)
@@ -0,0 +1,126 @@
+# locale/en_US/TopologyEditor.properties
+Plugins=Plugins
+Statistics=Statistics
+Files=Files
+PickOne=(pick one...)
+Import=Import...
+Save=Save
+Show=Show
+View=V
+ViewTooltip=View details
+
+Workspace=Workspace
+
+AccumulatedResources=Accumulated resources
+AccumulatedResourcesTooltip=Specifies whether accumulated resources statistics should be created.
+ExtendedTasks=Extended tasks
+ExtendedTasksTooltip=Specifies whether extended tasks statistics should be created.
+GridletHistory=Gridlet history
+GridletHistoryTooltip=Specifies whether history of gridlets should be created.
+Jobs=Jobs
+JobsTooltip=Specifies whether jobs (accumulated task) statistics should be created.
+Simulation=Simulation
+SimulationTooltip=Specifies whether accumulated simulation statistics should be created.
+
+GridScheduling=Grid scheduling plugin
+GridSchedulingTooltip=Specifies which plugin is used to manage broker interface.
+LocalGrid=Local grid scheduling plugin
+LocalGridTooltip=Specifies which plugin is used to manage local policies.
+ExecutionTimeEstimation=Execution time estimation plugin
+ExecutionTimeEstimationTooltip=Specifies which plugin is used to estimate task execution time.
+
+NetworkTopology=Network topology
+NetworkTopologyTooltip=File describing network topology.
+Workload=Workload
+WorkloadTooltip=File describing workload.
+ResourceDescription=Resource description
+ResourceDescriptionTooltip=File describing resources.
+
+FromNetworkEditor=From network editor
+FromNetworkEditorDescription=Current network editor topology.
+FromWorkloadEditor=From workload editor
+FromWorkloadEditorDescription=Current workload editor scheme.
+
+#fields describing workload file columns
+Field1=Job Number
+Field2=Submit Time
+Field3=Wait Time
+Field4=Run Time
+Field5=Number of Allocated Processors
+Field6=Average CPU Time Used
+Field7=Used Memory
+Field8=Requested Number of Processors
+Field9=Requested Time
+Field10=Requested Memory
+Field11=Status
+Field12=User ID
+Field13=Group ID
+Field14=Executable (Application) Number
+Field15=Queue Number
+Field16=Partition Number
+Field17=Preceding Job Number
+Field18=Think Time from Preceding Job
+
+WorkloadData=Data
+Header=Header
+Statistics=Statistics
+
+Name=Name
+Value=Value
+
+GraphNotConnectedError=Graph is not fully connected. Please ensure that all objects are linked.
+WorkloadNotGeneratedError=Workload was not generated. Please go to Workload Editor and generate the workload.
+InvalidExperimentPropertiesError=Please check experiment properties and set them to valid values.
+
+JobCount=Job count
+LongestRun=Longest run time (wait time + run time)
+AvgRunTime=Average run time
+MaxReqMem=Maximal requested memory [kb per processor]
+MaxReqTime=Maximal requested time [seconds]
+
+RunButton=Run task
+RunButtonTooltip=Schedule a new GRMS task to run GSSim remotely
+SendButton=Save configuration
+SendButtonTooltip=Send current experiment configuration to the remote server
+
+ShowDebugButton=Show debug items
+ShowDebugButtonTooltip=Reveal additional GUI elements with debug information
+
+DataOverrideAlert=Data in network topology editor will be overwritten - continue?
+DataOverrideAlertTitle=Alert
+
+CreateNewExperiment=Create new experiment
+New=New
+AddFile=Add file to server
+ClearFiles=Clear all files from workspace
+Metaname=Experiments group
+Add=Add
+AddTooltip=Create new experiment with this settings and close this window
+Clone=Clone
+CloneTooltip=Create new experiment with this settings without closing this window
+Cancel=Cancel
+CancelTooltip=Drop current experiment settings and close this window
+Runs=Number of simulations
+Actions=Actions
+Load=L
+LoadTooltip=Load file
+Remove=-
+RemoveTooltip=Remove file
+Edit=Edit
+EditTooltip=Change properties of this item
+Perform=Perform
+PerformTooltip=Perform the experiment on the simulator
+PerformAll=Perform all
+PerformAllTooltip=Perform all experiments on the simulator
+Upload=Upload
+Clear=Clear
+About=About
+
+UseSelectedFiles=Use all files in workspace
+
+GlobalPlugin=Global scheduling plugin
+LocalPlugin=Local scheduling plugin
+ExecutionPlugin=Execution estimation plugin
+
+FileManager=Manage files
+Close=Close
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Common.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Common.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Common.properties	(revision 15)
@@ -0,0 +1,7 @@
+# locale/en_US/Common.properties
+ExperimentEditor=Experiment Editor
+TopologyEditor=Topology Editor
+WorkloadGeneratorEditor=Workload Generator Editor
+ArchiveViewer=Experiments archive
+English=English
+Polish=Polski
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Help.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Help.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/Help.properties	(revision 15)
@@ -0,0 +1,11 @@
+# locale/en_US/Common.properties
+#Experiment properties help messages
+ExperimentName=The name used to identify this experiment in Archive.
+ExperimentMetaname=Group determines a single "batch" of experiments. If you run multiple experiments at once, the results will be available under this group name. You can change the group of performed experiments using Archive.
+NumberOfSimulations=Used to set the number of simulations that should be done using given configuration. If you have a plugin-specific parameter that will change with the simulation counter you should set this value, otherwise leave default 1 simulation.
+GridScheduling=Select the plugin which should be used as global scheduler. The list contains all available plugins which are compatible with the selected local scheduler. If you want to submit a new plugin, please contact with us.
+LocalGrid=Select the plugin which should be used as local scheduler. The list contains all available plugins which are compatible with the selected global scheduler. If you want to submit a new plugin, please contact with us.
+ExecutionTimeEstimation=Select the plugin which should be used as time estimation plugin. The list contains all available plugins. If you want to submit a new plugin, please contact with us.
+Workload=Select which file should be used as workload. Workloads generally describes all tasks which should be scheduled in simulation. It can be provided as one of these file types: .swf, .zip, .xml.
+NetworkTopology=Select which file should be used as network description. Networks consists of routers, clusters and computing resources which are connected via links of defined flow parameters. It should be a Unicode text file compatible with network description file format. If you leave the checkbox unselected, the topology will not affect the simulation.
+ResourceDescription=Select which file should be used as resource description. Resource description defines the parameters of computing resources such as CPU count, memory size, enery usage etc. It should be an .xml file compatible with proper schema.
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/WorkloadEditor.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/WorkloadEditor.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/WorkloadEditor.properties	(revision 15)
@@ -0,0 +1,79 @@
+# locale/en_US/WorkloadEditor.properties
+Validate=Validate tree
+Preferences=Preferences
+AddNewPreference=Add new preference
+ComputingResourceHostParameters=Computing Resource Host Parameters
+AddNewComputingResourceHostParameter=Add new computing resource host parameter
+Edit=Edit
+Clear=Clear
+SimulationStartTime=Simulation start time
+JobCount=Job count
+SimulationTime=Simulation time
+TaskCount=Task count
+TaskLength=Task length
+JobPackageLength=Job package length
+JobInterval=Job interval
+ExecDuration=Exec duration
+PeriodStart=Period start
+PeriodEnd=Period end
+PeriodDuration=Period duration
+Buttons=Buttons
+Metric=Metric
+Type=Type
+Basic=Basic
+Dependencies=Dependencies
+TreeView=Tree view
+Menu=Menu
+MenuTooltip=Open menu
+New=New
+NewTooltip=Create new workload
+Open=Open
+OpenTooltip=Open workload from file...
+Save=Save
+SaveTooltip=Save workload to file...
+InvalidWorkloadError=Error occurred, please check the error list for further information.
+Value=Value
+Minimum=Minimum
+Maximum=Maximum
+Close=Close
+AddNewDist=Add new distribution
+ID=Id
+ReferenceID=Reference Id
+Expression=Expression
+Average=Average
+StandardDeviation=Standard deviation
+RandomSeed=Random seed
+Distribution=Distribution
+Attributes=Attributes
+PeriodicValidValuesDates=Periodic valid values dates
+BeginDate=Begin date
+EndDate=End date
+Name=Name
+Endpoint=Endpoint
+Importance=Importance
+OptimizationType=Optimization type
+PreferenceType=Preference type
+AddNewPreferenceParameter=Add new preference parameter
+BeginTime=Begin time
+EndTime=End time
+AddNewPeriod=Add new period
+MultiDistribution=MultiDistribution
+Show=Show
+ShowTooltip=Show tree view
+Generate=Generate
+GenerateTooltip=Generate workload based on defined parameters.
+UnknownError=Unknown error occured.
+MissingPreferenceTypeError=Missing preference type.
+MissingNameError=Missing Name.
+MissingImportanceError=Missing Importance.
+MissingOptimizationTypeError=Missing Optimization type.
+MissingValueError=Missing Value.
+CannotBeSetTogetherError=- cannot be set together.
+UnknownReferenceError=This element references to unknown ID!
+SelfReferenceError=This element references to itself!
+DoubleIDError=Element with that ID already exists!
+MissingError=Missing.
+OneMustBeSetError=- one of these elements must be set.
+Remove=Remove
+ProbabilisticParameters=Probabilistic parameters
+Dates=Dates
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/gssimstudio.properties
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/gssimstudio.properties	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/locale/en_US/gssimstudio.properties	(revision 15)
@@ -0,0 +1,3 @@
+#Mon, 06 Sep 2010 10:08:38 +0200
+
+testKey=test value for locale en_US
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/extendedSlider.css
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/extendedSlider.css	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/extendedSlider.css	(revision 15)
@@ -0,0 +1,4 @@
+.sliderLabel
+{
+	fontSize: 10
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/charts.css
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/charts.css	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/charts.css	(revision 15)
@@ -0,0 +1,48 @@
+.zoomButton 
+{
+	cornerRadius: 20;
+	textAlign: center;
+	paddingLeft: 0;
+	paddingTop: 0;
+	paddingRight: 0;
+	paddingBottom: 0;
+}
+
+.selectionBox 
+{
+	borderStyle : solid;
+	borderColor : #000000;
+	themeColor : #7FFC97;
+	borderThickness : 0;
+	alpha : 1.0;
+	backgroundColor : #56FF3A;
+	backgroundAlpha : 0.17;
+}
+
+.title
+{
+	textAlign: center;
+	fontSize: 14;
+	fontWeight: bold;
+}
+
+.subtitle
+{
+	textAlign: center;
+	fontSize: 11;
+	fontWeight: normal;
+}
+
+.verticalAxisTitle
+{ 
+	fontFamily: myArialFont; 
+	fontSize: 10; 
+	fontWeight: normal;
+} 
+
+.horizontalAxisTitle
+{
+	fontFamily: myArialFont; 
+	fontSize: 10; 
+	fontWeight: normal;
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/experimentWindow.css
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/experimentWindow.css	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/assets/css/experimentWindow.css	(revision 15)
@@ -0,0 +1,4 @@
+Label.importedFileLabel {
+	padding-left: 15px;
+	font-size: 8px;
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example-config.xml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example-config.xml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example-config.xml	(revision 15)
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<flex-config xmlns="http://www.adobe.com/2006/flex-config">
+    <use-network>true</use-network>
+    <compiler strict="true">
+        <context-root>gridsphere</context-root>
+        <services>C:\liferay-portal-5.2.3\tomcat-5.5.27/webapps/gridsphere/WEB-INF/flex/services-config.xml</services>
+    </compiler>
+    <output>Example.swf</output>
+</flex-config>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example.as	(revision 15)
@@ -0,0 +1,7 @@
+import mx.events.FlexEvent;
+
+public function creationComplete(event:FlexEvent) : void {
+    //    model binding
+    bindModel("exampleModel")
+
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/ExampleModel.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/ExampleModel.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/ExampleModel.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.example
+{
+
+ [Bindable]
+ [RemoteClass(alias = "gssim.gssimstudio.flex.app.example.ExampleModel")]
+ public class ExampleModel {
+
+ public function ExampleModel() {
+    }
+
+ public var messageAuthenticated:String;
+ public var message:String;
+ }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/example/Example.mxml	(revision 15)
@@ -0,0 +1,24 @@
+<?xml version="1.0" ?>
+<vine:VineApplication xmlns="gssim.gssimstudio.example.*"
+                      xmlns:vine="org.vinetoolkit.vine.*"
+                      xmlns:mx="http://www.adobe.com/2006/mxml"
+                      creationComplete="creationComplete(event)">
+ <mx:Metadata>
+  [ResourceBundle("gssimstudio")]
+</mx:Metadata>
+    <!--where to store data from server, results need to be binded to this model-->
+    <ExampleModel id="exampleModel"/>
+    <mx:Script source="Example.as"/>
+    <mx:VBox>
+        <mx:Text text="Example component"/>
+        <mx:Button label="Fetch message (logged in user)" click="{service.doTestMethodPublishedLoggedIn()}"></mx:Button>
+        <mx:Text text="message:"/>
+        <mx:Text text="{model.messageAuthenticated} aa"/>
+        <mx:Button label="Fetch message" click="{service.doTestMethodPublished()}"></mx:Button>
+        <mx:Text text="message:"/>
+        <mx:Text text="{model.message} bb"/>
+
+        <mx:Text text="localized message:"/>
+        <mx:Label text="{resourceManager.getString('gssimstudio', 'testKey')}"/>
+    </mx:VBox>
+</vine:VineApplication>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/BlobProperty.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/BlobProperty.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/BlobProperty.as	(revision 15)
@@ -0,0 +1,41 @@
+package gssim.gssimstudio.db.dao.data {
+import flash.utils.ByteArray;
+
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.BlobProperty")]
+public class BlobProperty {
+
+	protected var configId:int;
+	protected var name:String;
+	protected var value:ByteArray;
+	
+	public function getConfigId():int {
+		return configId;
+	}
+	
+	public function setConfigId(configId:int):void {
+		this.configId = configId;
+	}
+	
+	public function getName():String {
+		return name;
+	}
+	
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	
+	public function getValue():ByteArray {
+		return value;
+	}
+
+	public function setValue(value:ByteArray):void {
+		this.value = value;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitDetails.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitDetails.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitDetails.as	(revision 15)
@@ -0,0 +1,39 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.UnitDetails")]
+public class UnitDetails {
+
+	protected var fkUnitId:int;
+	protected var name:String;
+	protected var value:String;
+	
+	public function getFkUnitId():int {
+		return fkUnitId;
+	}
+	
+	public function setFkUnitId(fkUnitId:int):void {
+		this.fkUnitId = fkUnitId;
+	}
+	
+	public function getName():String {
+		return name;
+	}
+	
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	
+	public function getValue():String {
+		return value;
+	}
+	
+	public function setValue(value:String):void {
+		this.value = value;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Allocation.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Allocation.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Allocation.as	(revision 15)
@@ -0,0 +1,66 @@
+/*
+ * @author Jarek Szymczak
+ */
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Allocation")]
+public class Allocation {
+
+	protected var PK:int;
+	protected var taskId:int;
+	protected var unitId:int;
+	protected var begin:Date;
+	protected var end:Date;
+	
+
+	public function getPK():int {
+		return PK;
+	}
+
+	/**
+	 * Sets the primary key in the allocation class and foreign keys in allocation details list.
+	 *
+	 * @param pK primary key
+	 */
+	public function setPK(pK:int):void {
+		PK = pK;
+	}
+
+	public function getTaskId():int {
+		return taskId;
+	}
+
+	public function setTaskId(taskId:int):void {
+		this.taskId = taskId;
+	}
+
+	public function getUnitId():int {
+		return unitId;
+	}
+
+	public function setUnitId(unitId:int):void {
+		this.unitId = unitId;
+	}
+
+	public function getBegin():Date {
+		return begin;
+	}
+
+	public function setBegin(begin:Date):void {
+		this.begin = begin;
+	}
+
+	public function getEnd():Date {
+		return end;
+	}
+
+	public function setEnd(end:Date):void {
+		this.end = end;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Resource.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Resource.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Resource.as	(revision 15)
@@ -0,0 +1,66 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Resource")]
+public class Resource {
+
+	protected var PK:int;
+	protected var expId:int;
+	protected var name:String;
+	protected var type:String;
+	protected var allocationLoad:Number;
+	protected var reservationLoad:Number;
+	
+	public function getPK():int {
+		return PK;
+	}
+	
+	public function setPK(pK:int):void {
+		PK = pK;
+	}
+	
+	public function getExpId():int {
+		return expId;
+	}
+	
+	public function setExpId(expId:int):void {
+		this.expId = expId;
+	}
+	
+	public function getName():String {
+		return name;
+	}
+	
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	
+	public function getType():String {
+		return type;
+	}
+	
+	public function setType(type:String):void {
+		this.type = type;
+	}
+	
+	public function getAllocationLoad():Number {
+		return allocationLoad;
+	}
+	
+	public function setAllocationLoad(allocationLoad:Number):void {
+		this.allocationLoad = allocationLoad;
+	}
+	
+	public function getReservationLoad():Number {
+		return reservationLoad;
+	}
+	
+	public function setReservationLoad(reservationLoad:Number):void {
+		this.reservationLoad = reservationLoad;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitEnTimeline.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitEnTimeline.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitEnTimeline.as	(revision 15)
@@ -0,0 +1,40 @@
+package gssim.gssimstudio.db.dao.data {
+
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.UnitEnTimeline")] 
+public class UnitEnTimeline {
+	
+	protected var fkUnitId:int;
+	protected var timestamp:Date;
+	protected var usage:Number;
+	
+	public function getFkUnitId():int {
+		return fkUnitId;
+	}
+	
+	public function setFkUnitId(fkUnitId:int):void {
+		this.fkUnitId = fkUnitId;
+	}
+	
+	public function getTimestamp():Date {
+		return timestamp;
+	}
+	
+	public function setTimestamp(timestamp:Date):void {
+		this.timestamp = timestamp;
+	}
+	
+	public function getUsage():Number {
+		return usage;
+	}
+	
+	public function setUsage(usage:Number):void {
+		this.usage = usage;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/TextProperty.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/TextProperty.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/TextProperty.as	(revision 15)
@@ -0,0 +1,34 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.TextProperty")] 
+public class TextProperty {
+	
+	protected var configId:int;
+	protected var name:String;
+	protected var value:String;
+	
+	public function getConfigId():int {
+		return configId;
+	}
+	public function setConfigId(configId:int):void {
+		this.configId = configId;
+	}
+	public function getName():String {
+		return name;
+	}
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	public function getValue():String {
+		return value;
+	}
+	public function setValue(value:String):void {
+		this.value = value;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/AllocationDetails.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/AllocationDetails.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/AllocationDetails.as	(revision 15)
@@ -0,0 +1,39 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.AllocationDetails")]
+public class AllocationDetails {
+
+	var fkAllocationId:int;
+	var name:String;
+	var value:String;
+	
+	public function getFkAllocationId():int {
+		return fkAllocationId;
+	}
+	
+	public function setFkAllocationId(fkAllocationId:int):void {
+		this.fkAllocationId = fkAllocationId;
+	}
+	
+	public function getName():String {
+		return name;
+	}
+	
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	
+	public function getValue():String {
+		return value;
+	}
+	
+	public function setValue(value:String):void {
+		this.value = value;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Plugin.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Plugin.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Plugin.as	(revision 15)
@@ -0,0 +1,57 @@
+package gssim.gssimstudio.db.dao.data;
+
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Plugin")]
+public class Plugin {
+
+	protected var PK : int;
+	protected var name : String;
+	protected var description : String;
+	protected var input : String;
+	protected var isGlobal : Boolean;
+	
+	public function getPK() : int {
+		return PK;
+	}
+	
+	public function setPK(Integer pK) : void {
+		this.PK = pK;
+	}
+	
+	public function getName() : String {
+		return name;
+	}
+	
+	public function setName(String name) : void {
+		this.name = name;
+	}
+	
+	public function getDescription() : String {
+		return description;
+	}
+	
+	public function setDescription(String description) : void {
+		this.description = description;
+	}
+	
+	public function getInput() : String {
+		return input;
+	}
+	
+	public function setInput(String input) : void {
+		this.input = input;
+	}
+	
+	public function getIsGlobal() : Boolean {
+		return isGlobal;
+	}
+	
+	public function setIsGlobal(Boolean isGlobal) : void {
+		this.isGlobal = isGlobal;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitAllTimeline.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitAllTimeline.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/UnitAllTimeline.as	(revision 15)
@@ -0,0 +1,40 @@
+package gssim.gssimstudio.db.dao.data {
+
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.UnitAllTimeline")] 
+public class UnitAllTimeline {
+
+	protected var fkUnitId:int;
+	protected var timestamp:Date;
+	protected var usage:Number;
+	
+	public function getFkUnitId():int {
+		return fkUnitId;
+	}
+	
+	public function setFkUnitId(fkUnitId:int):void {
+		this.fkUnitId = fkUnitId;
+	}
+	
+	public function getTimestamp():Date {
+		return timestamp;
+	}
+	
+	public function setTimestamp(timestamp:Date):void {
+		this.timestamp = timestamp;
+	}
+	
+	public function getUsage():Number {
+		return usage;
+	}
+	
+	public function setUsage(usage:Number):void {
+		this.usage = usage;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ExperimentStats.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ExperimentStats.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ExperimentStats.as	(revision 15)
@@ -0,0 +1,39 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.ExperimentStats")]
+public class ExperimentStats {
+
+	protected var id:int;
+	protected var name:String;
+	protected var value:Number;
+	
+	public function getId():int {
+		return id;
+	}
+	
+	public function setId(id:int):void {
+		this.id = id;
+	}
+	
+	public function getName():String {
+		return name;
+	}
+	
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	
+	public function getValue():Number {
+		return value;
+	}
+	
+	public function setValue(value:Number):void {
+		this.value = value;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Reservation.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Reservation.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Reservation.as	(revision 15)
@@ -0,0 +1,93 @@
+package gssim.gssimstudio.db.dao.data {
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 
+ * @author Jarek Szymczak
+ * 
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Reservation")]
+public class Reservation {
+
+	protected var PK:int;
+	protected var taskId:int;
+	protected var unitId:int;
+	protected var begin:Date;
+	protected var end:Date;
+	protected List<ReservationDetails> reservationDetails = new ArrayList<ReservationDetails>();
+
+	public function getPK():int {
+		return PK;
+	}
+
+	/**
+	 * Sets the primary key in the reservation class and foreign keys in
+	 * reservation details list.
+	 * 
+	 * @param pK
+	 *            primary key
+	 */
+	public function setPK(pK:int):void {
+		PK = pK;
+		if (reservationDetails.size() > 0)
+			for (ReservationDetails reservationDetail : reservationDetails) {
+				reservationDetail.setFkReservationId(pK);
+			}
+	}
+
+	public function getTaskId():int {
+		return taskId;
+	}
+
+	public function setTaskId(taskId:int):void {
+		this.taskId = taskId;
+	}
+
+	public function getUnitId():int {
+		return unitId;
+	}
+
+	public function setUnitId(unitId:int):void {
+		this.unitId = unitId;
+	}
+
+	public function getBegin():Date {
+		return begin;
+	}
+
+	public function setBegin(begin:Date):void {
+		this.begin = begin;
+	}
+
+	public function getEnd():Date {
+		return end;
+	}
+
+	public function setEnd(end:Date):void {
+		this.end = end;
+	}
+
+	public function addReservationDetails(reservationDetail:ReservationDetails):void {
+		reservationDetails.add(reservationDetail);
+	}
+
+	/**
+	 * Gets the reservation details on list.
+	 * 
+	 * @param accReservationDetails
+	 *            the list, on which reservation details are copied (the list
+	 *            should be initialized)
+	 */
+	public function getReservationDetailsOnList(
+			List<ReservationDetails> accReservationDetails):void {
+		if (accReservationDetails == null)
+			return;
+		for (ReservationDetails reservationDetail : reservationDetails) {
+			accReservationDetails.add(reservationDetail);
+		}
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ResourceEnTimeline.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ResourceEnTimeline.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ResourceEnTimeline.as	(revision 15)
@@ -0,0 +1,40 @@
+package gssim.gssimstudio.db.dao.data {
+
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.ResourceEnTimeline")]
+public class ResourceEnTimeline {
+	
+	  protected var fkResourceId:int;
+	  protected var timestamp:Date;
+	  protected var usage:Number;
+	  
+	public function getFkResourceId():int {
+		return fkResourceId;
+	}
+	
+	public function setFkResourceId(fkResourceId:int):void {
+		this.fkResourceId = fkResourceId;
+	}
+	
+	public function getTimestamp():Date {
+		return timestamp;
+	}
+	
+	public function setTimestamp(timestamp:Date):void {
+		this.timestamp = timestamp;
+	}
+	
+	public function getUsage():Number {
+		return usage;
+	}
+	
+	public function setUsage(usage:Number):void {
+		this.usage = usage;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Task.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Task.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Task.as	(revision 15)
@@ -0,0 +1,211 @@
+package gssim.gssimstudio.db.dao.data {
+
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Task")]
+public class Task {
+
+	protected var PK:int;
+	protected var expId:int;
+	protected var jobId:int;
+	protected var taskId:int;
+	protected var procSetId:int;
+	protected var parentId:int;
+	protected var execStartDate:Date;
+	protected var execFinishDate:Date;
+	protected var execEndDate:Date;
+	protected var gbSubmitDate:Date;
+	protected var lbSubmitDate:Date;
+	protected var completionTime:int;
+	protected var execStartTime:int;
+	protected var executionTime:int;
+	protected var startTime:int;
+	protected var readyTime:int;
+	protected var flowTime:int;
+	protected var waitingTime:int;
+	protected var gqWaitingTime:int;
+	protected var lateness:int;
+	protected var tardiness:int;
+	protected var makespan:int;
+	
+	public function getPK():int {
+		return PK;
+	}
+	
+	public function setPK(pK:int):void {
+		PK = pK;
+	}
+	
+	public function getExpId():int {
+		return expId;
+	}
+	
+	public function setExpId(expId:int):void {
+		this.expId = expId;
+	}
+	
+	public function getJobId():int {
+		return jobId;
+	}
+	
+	public function setJobId(jobId:int):void {
+		this.jobId = jobId;
+	}
+	
+	public function getTaskId():int {
+		return taskId;
+	}
+	
+	public function setTaskId(taskId:int):void {
+		this.taskId = taskId;
+	}
+	
+	public function getProcSetId():int {
+		return procSetId;
+	}
+	
+	public function setProcSetId(procSetId:int):void {
+		this.procSetId = procSetId;
+	}
+	
+	public function getParentId():int {
+		return parentId;
+	}
+	
+	public function setParentId(parentId:int):void {
+		this.parentId = parentId;
+	}
+	
+	public function getExecStartDate():Date {
+		return execStartDate;
+	}
+	
+	public function setExecStartDate(execStartDate:Date):void {
+		this.execStartDate = execStartDate;
+	}
+	
+	public function getExecFinishDate():Date {
+		return execFinishDate;
+	}
+	
+	public function setExecFinishDate(execFinishDate:Date):void {
+		this.execFinishDate = execFinishDate;
+	}
+	
+	public function getExecEndDate():Date {
+		return execEndDate;
+	}
+	
+	public function setExecEndDate(execEndDate:Date):void {
+		this.execEndDate = execEndDate;
+	}
+	
+	public function getGbSubmitDate():Date {
+		return gbSubmitDate;
+	}
+	
+	public function setGbSubmitDate(gbSubmitDate:Date):void {
+		this.gbSubmitDate = gbSubmitDate;
+	}
+	
+	public function getLbSubmitDate():Date {
+		return lbSubmitDate;
+	}
+	
+	public function setLbSubmitDate(lbSubmitDate:Date):void {
+		this.lbSubmitDate = lbSubmitDate;
+	}
+	
+	public function getCompletionTime():int {
+		return completionTime;
+	}
+	
+	public function setCompletionTime(completionTime:int):void {
+		this.completionTime = completionTime;
+	}
+	
+	public function getExecStartTime():int {
+		return execStartTime;
+	}
+	
+	public function setExecStartTime(execStartTime:int):void {
+		this.execStartTime = execStartTime;
+	}
+	
+	public function getExecutionTime():int {
+		return executionTime;
+	}
+	
+	public function setExecutionTime(executionTime:int):void {
+		this.executionTime = executionTime;
+	}
+	
+	public function getStartTime():int {
+		return startTime;
+	}
+	
+	public function setStartTime(startTime:int):void {
+		this.startTime = startTime;
+	}
+	
+	public function getReadyTime():int {
+		return readyTime;
+	}
+	
+	public function setReadyTime(readyTime:int):void {
+		this.readyTime = readyTime;
+	}
+	
+	public function getFlowTime():int {
+		return flowTime;
+	}
+	
+	public function setFlowTime(flowTime:int):void {
+		this.flowTime = flowTime;
+	}
+	
+	public function getWaitingTime():int {
+		return waitingTime;
+	}
+	
+	public function setWaitingTime(waitingTime:int):void {
+		this.waitingTime = waitingTime;
+	}
+	
+	public function getGqWaitingTime():int {
+		return gqWaitingTime;
+	}
+	
+	public function setGqWaitingTime(gqWaitingTime:int):void {
+		this.gqWaitingTime = gqWaitingTime;
+	}
+	
+	public function getLateness():int {
+		return lateness;
+	}
+	
+	public function setLateness(lateness:int):void {
+		this.lateness = lateness;
+	}
+	
+	public function getTardiness():int {
+		return tardiness;
+	}
+	
+	public function setTardiness(tardiness:int):void {
+		this.tardiness = tardiness;
+	}
+	
+	public function getMakespan():int {
+		return makespan;
+	}
+	
+	public function setMakespan(makespan:int):void {
+		this.makespan = makespan;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ResourceAllTimeline.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ResourceAllTimeline.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ResourceAllTimeline.as	(revision 15)
@@ -0,0 +1,40 @@
+package gssim.gssimstudio.db.dao.data {
+
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.ResourceAllTimeline")]
+public class ResourceAllTimeline {
+
+	  protected var fkResourceId:int;
+	  protected var timestamp:Date;
+	  protected var usage:Number;
+	  
+	public function getFkResourceId():int {
+		return fkResourceId;
+	}
+	
+	public function setFkResourceId(fkResourceId:int):void {
+		this.fkResourceId = fkResourceId;
+	}
+	
+	public function getTimestamp():Date {
+		return timestamp;
+	}
+	
+	public function setTimestamp(timestamp:Date):void {
+		this.timestamp = timestamp;
+	}
+	
+	public function getUsage():Number {
+		return usage;
+	}
+	
+	public function setUsage(usage:Number):void {
+		this.usage = usage;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ReservationDetails.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ReservationDetails.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/ReservationDetails.as	(revision 15)
@@ -0,0 +1,39 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.ReservationDetails")]
+public class ReservationDetails {
+	
+	var fkReservationId:int;
+	var name:String;
+	var value:String;
+	
+	public function getFkReservationId():int {
+		return fkReservationId;
+	}
+	
+	public function setFkReservationId(fkReservationId:int):void {
+		this.fkReservationId = fkReservationId;
+	}
+	
+	public function getName():String {
+		return name;
+	}
+	
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	
+	public function getValue():String {
+		return value;
+	}
+	
+	public function setValue(value:String):void {
+		this.value = value;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Queues.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Queues.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Queues.as	(revision 15)
@@ -0,0 +1,39 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Queues")]
+public class Queues {
+
+	protected var fkResourceId:int;
+	protected var name:String;
+	protected var avgLength:Number;
+	
+	public function getFkResourceId():int {
+		return fkResourceId;
+	}
+	
+	public function setFkResourceId(fkResourceId:int):void {
+		this.fkResourceId = fkResourceId;
+	}
+	
+	public function getName():String {
+		return name;
+	}
+	
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	
+	public function getAvgLength():Number {
+		return avgLength;
+	}
+	
+	public function setAvgLength(avgLength:Number):void {
+		this.avgLength = avgLength;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Configuration.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Configuration.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Configuration.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Configuration")]
+public class Configuration {
+
+	protected var id:int;
+
+	public function getId():int {
+		return id;
+	}
+
+	public function setId(id:int):void {
+		this.id = id;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/User.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/User.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/User.as	(revision 15)
@@ -0,0 +1,29 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+ 
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.User")]
+public class User {
+
+	protected var id:int;
+	protected var DN:String;
+	
+	public function getId():int {
+		return id;
+	}
+	public function setId(id:int):void {
+		this.id = id;
+	}
+	
+	public function getDN():String {
+		return DN;
+	}
+	public function setDN(dn:String):void {
+		DN = dn;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Unit.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Unit.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Unit.as	(revision 15)
@@ -0,0 +1,83 @@
+package gssim.gssimstudio.db.dao.data {
+
+/**
+ * 
+ * @author Jarek Szymczak
+ * 
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Unit")]
+public class Unit {
+
+	protected var PK:int;
+	protected var resourceId:int;
+	protected var type:String;
+	protected var name:String;
+	protected var amount:int;
+	protected var allocationLoad:Number;
+	protected var reservationLoad:Number;
+
+	public function getPK():int {
+		return PK;
+	}
+
+	/**
+	 * Sets the primary key in the unit class and foreign keys in unit details
+	 * list.
+	 * 
+	 * @param pK
+	 *            primary key
+	 */
+	public function setPK(pK:int):void {
+		this.PK = pK;
+	}
+
+	public function getResourceId():int {
+		return resourceId;
+	}
+
+	public function setResourceId(resourceId:int):void {
+		this.resourceId = resourceId;
+	}
+
+	public function getType():String {
+		return type;
+	}
+
+	public function setType(type:String):void {
+		this.type = type;
+	}
+
+	public function getName():String {
+		return name;
+	}
+
+	public function setName(name:String):void {
+		this.name = name;
+	}
+
+	public function getAmount():int {
+		return amount;
+	}
+
+	public function setAmount(amount:int):void {
+		this.amount = amount;
+	}
+
+	public function getAllocationLoad():Number {
+		return allocationLoad;
+	}
+
+	public function setAllocationLoad(allocationLoad:Number):void {
+		this.allocationLoad = allocationLoad;
+	}
+
+	public function getReservationLoad():Number {
+		return reservationLoad;
+	}
+
+	public function setReservationLoad(reservationLoad:Number):void {
+		this.reservationLoad = reservationLoad;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Experiment.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Experiment.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/db/dao/data/Experiment.as	(revision 15)
@@ -0,0 +1,88 @@
+package gssim.gssimstudio.db.dao.data {
+/**
+ * 
+ * @author Jarek Szymczak
+ *
+ */
+[Bindable]
+[RemoteClass(alias = "gssim.db.dao.data.Experiment")]
+public class Experiment {	
+	protected var PK:int;
+	protected var userId:int;
+	protected var configId:int;
+	protected var commissionDate:Date;
+	protected var name:String;
+	protected var description:String;
+	protected var status:String;
+	protected var metaexpId:int;
+	
+	public function getPK():int {
+		return PK;
+	}
+	
+	public function setPK(pk:int):void {
+		this.PK = pk;
+	}
+	
+	public function getUserId():int {
+		return userId;
+	}
+	
+	public function setUserId(userId:int):void {
+		this.userId = userId;
+	}
+	
+	public function getConfigId():int {
+		return configId;
+	}
+	
+	public function setConfigId(configId:int):void {
+		this.configId = configId;
+	}
+	
+	public function getCommissionDate():Date {
+		return commissionDate;
+	}
+	
+	public function setCommissionDate(commissionDate:Date):void {
+		this.commissionDate = commissionDate;
+	}
+	
+	public function getName():String {
+		return name;
+	}
+	
+	public function setName(name:String):void {
+		this.name = name;
+	}
+	
+	public function getDescription():String {
+		return description;
+	}
+	
+	public function setDescription(description:String):void {
+		this.description= description;
+	}
+	
+	public function getStatus():String {
+		return status;
+	}
+	
+	public function setStatus(status:String):void {
+		this.status = status;
+	}
+	
+	public function getMetaexpId():int {
+		return metaexpId;
+	}
+	
+	public function setMetaexpId(metaexpId:int):void {
+		this.metaexpId = metaexpId;
+	}
+	
+	public function toString() : String
+	{
+		return PK + " " + userId + " " + status + " " + metaexpId;
+	}
+}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudio-config.xml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudio-config.xml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudio-config.xml	(revision 15)
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<flex-config xmlns="http://www.adobe.com/2006/flex-config">
+    <use-network>true</use-network>
+    <output>GSSimStudio.swf</output>
+	<compiler strict="true">
+		<context-root>gridsphere</context-root>
+        <services>C:\liferay-portal-5.2.3\tomcat-5.5.27/webapps/gridsphere/WEB-INF/flex/services-config.xml</services>
+		<theme>
+			<filename>
+				${FLEX_HOME}/frameworks/themes/Halo/halo.swc
+			</filename>
+		</theme>
+	</compiler>
+</flex-config>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/replace.ps1
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/replace.ps1	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/replace.ps1	(revision 15)
@@ -0,0 +1,156 @@
+function ReplaceText($fileInfo)
+{
+    if( $_.GetType().Name -ne 'FileInfo')
+    {
+        # i.e. reject DirectoryInfo and other types
+         return
+    }
+
+	if( $fileInfo.Extension -eq '.as' -or $fileInfo.Extension -eq '.mxml')
+    {
+        $old = $p1
+		$mew = $p2
+		(Get-Content $fileInfo.FullName) | % {$_ -replace $old, $mew} | Set-Content -path $fileInfo.FullName
+		"Processed: " + $old + " in " + $fileInfo.FullName
+    }
+}
+
+$loc = '.'
+cd $loc
+$files = Get-ChildItem . -recurse
+
+$p1 = "package gssim"
+$p2 = "package gssim.gssimstudio.editor.gssim"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "package flare"
+$p2 = "package gssim.gssimstudio.editor.flare"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "package script"
+$p2 = "package gssim.gssimstudio.editor.script"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "package views"
+$p2 = "package gssim.gssimstudio.editor.views"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "package charts"
+$p2 = "package gssim.gssimstudio.editor.charts"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "import gssim"
+$p2 = "import gssim.gssimstudio.editor.gssim"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "import flare"
+$p2 = "import gssim.gssimstudio.editor.flare"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "import script"
+$p2 = "import gssim.gssimstudio.editor.script"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "import views"
+$p2 = "import gssim.gssimstudio.editor.views"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = "import charts"
+$p2 = "import gssim.gssimstudio.editor.charts"
+$files | % { ReplaceText( $_ ) }
+
+$p1 = '"gssim.components.IconToggleButton"'
+$p2 = '"gssim.gssimstudio.editor.gssim.components.IconToggleButton"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:components="gssim.components'
+$p2 = 'xmlns:components="gssim.gssimstudio.editor.gssim.components'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns="gssim.flexmdi'
+$p2 = 'xmlns="gssim.gssimstudio.editor.gssim.flexmdi'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:v="gssim.editors.topology'
+$p2 = 'xmlns:v="gssim.gssimstudio.editor.gssim.editors.topology'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns="gssim.editors.topology'
+$p2 = 'xmlns="gssim.gssimstudio.editor.gssim.editors.topology'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:c="charts'
+$p2 = 'xmlns:c="gssim.gssimstudio.editor.charts'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'source="assets'
+$p2 = 'source="/gssim/gssimstudio/editor/assets'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:cp="charts.com.connectedpixel.charts'
+$p2 = 'xmlns:cp="gssim.gssimstudio.editor.charts.com.connectedpixel.charts'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:ssl="charts.smoothScrollingList'
+$p2 = 'xmlns:ssl="gssim.gssimstudio.editor.charts.smoothScrollingList'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:v="charts.scheduling'
+$p2 = 'xmlns:v="gssim.gssimstudio.editor.charts.scheduling'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'styleValue: charts.com.connectedpixel.charts.skins'
+$p2 = 'styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:gssim="gssim.editors.topology'
+$p2 = 'xmlns:gssim="gssim.gssimstudio.editor.gssim.editors.topology'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:workload="gssim.editors.workload'
+$p2 = 'xmlns:workload="gssim.gssimstudio.editor.gssim.editors.workload'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'xmlns:minimap="gssim.minimap'
+$p2 = 'xmlns:minimap="gssim.gssimstudio.editor.gssim.minimap'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'gssim.topology.NetworkObjectLinker.CHANGE'
+$p2 = 'gssim.gssimstudio.editor.gssim.topology.NetworkObjectLinker.CHANGE'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'skinClass="gssim.skins.IconButtonSkin"'
+$p2 = 'skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'skinClass="gssim.skins.IconToggleButtonSkin"'
+$p2 = 'skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = '"gssim.components.IconButton"'
+$p2 = '"gssim.gssimstudio.editor.gssim.components.IconButton"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'itemRenderer="gssim.editors.workload.DataGridCHRPButtonsRenderer"'
+$p2 = 'itemRenderer="gssim.gssimstudio.editor.gssim.editors.workload.DataGridCHRPButtonsRenderer"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'itemRenderer="gssim.editors.workload.DataGridPrefsButtonsRenderer"'
+$p2 = 'itemRenderer="gssim.gssimstudio.editor.gssim.editors.workload.DataGridPrefsButtonsRenderer"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'entryLayout="charts.scheduling.scheduleClasses.layout.SimpleLayout"'
+$p2 = 'entryLayout="gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.SimpleLayout"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'entryRenderer="charts.scheduling.scheduleClasses.renderers.ColoredSolidScheduleEntryRenderer"'
+$p2 = 'entryRenderer="gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers.ColoredSolidScheduleEntryRenderer"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'type="charts.scheduling.scheduleClasses.LayoutScrollEvent"'
+$p2 = 'type="gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.LayoutScrollEvent"'
+$files | % { ReplaceText( $_ ) }
+
+$p1 = 'source="../icon/'
+$p2 = 'source="gssim/gssimstudio/editor/assets/icon/'
+$files | % { ReplaceText( $_ ) }
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/ExperimentID.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/ExperimentID.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/ExperimentID.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.editor.gssim.experiment
+{
+	public class ExperimentID
+	{
+		public var pk : Number;
+		public var name : String;
+		public var folder : String;
+		
+		public function ExperimentID(pk : Number, name : String, folder : String)
+		{
+			this.pk = pk;
+			this.name = name;
+			this.folder = folder;
+		}
+		
+		public function toString() : String
+		{
+			return name + " [" + folder + "]";
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/ExperimentProperties.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/ExperimentProperties.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/ExperimentProperties.as	(revision 15)
@@ -0,0 +1,162 @@
+package gssim.gssimstudio.editor.gssim.experiment
+{	
+	import gssim.gssimstudio.db.dao.data.Experiment;
+
+	/**
+	 * Class used to store experiment properties
+	 */
+	public class ExperimentProperties
+	{
+		[Bindable]
+		public var workload : String;
+		[Bindable]
+		public var topology : String;
+		[Bindable]
+		public var resources : String;
+		[Bindable]
+		public var global : String;
+		[Bindable]
+		public var local : String;
+		[Bindable]
+		public var exec : String;
+		[Bindable]
+		public var metaname : String;
+		[Bindable]
+		public var name : String;
+		[Bindable]
+		public var runs : Number;
+		
+		private var properties : Object; // map id->value
+		
+		// - specifies which plugin is used to manage broker interface
+		public static const statsOutputFolder : String = "stats.outputfolder";
+		// - specifies which plugin is used to manage broker interface
+		public static const gridSchedulingPlugin : String = "gridschedulingpluginname";
+		// - specifies which plugin is used to estimate task execution time
+		public static const execTimeEstimationPlugin : String = "exectimeestimationpluginname";
+		// - specifies which plugin is used to manage local policies
+		public static const localAllocPolicyPlugin : String = "localallocpolicypluginname";
+		// - specifies file which is used to define network topology
+		public static const networkTopologyFile : String = "networkTopologyFile";
+		// - specifies file which is used to describe workload in SWF format
+		public static const workloadFile : String = "readscenario.workloadfilename";
+		// - specifies file which is used to describe workload in SWF format
+		public static const resourceDescriptionFile : String = "resdesc";
+		// - specifies file which is used to describe workload in SWF format
+		public static const numberOfSimulations  : String = "numberofsimulations";
+		
+		
+		public function ExperimentProperties()
+		{
+			properties = new Object();
+			
+			 //set default output folder:
+			properties[statsOutputFolder] = "../../output/experiment_result";
+			//set default values for plugins
+			properties[gridSchedulingPlugin] = null;
+			properties[execTimeEstimationPlugin] = null;
+			properties[localAllocPolicyPlugin] = null;
+			properties[networkTopologyFile] = null;
+			properties[workloadFile] = null;
+			properties[resourceDescriptionFile] = null;
+			properties[numberOfSimulations] = null;
+		}
+
+		/**
+		 * Returns property value given by name
+		 */
+		public function getProperty(propertyName :String) : Object
+		{
+			return properties[propertyName];
+		}
+		
+		/**
+		 * @Deprecated
+		 * Sets property value given by name
+		 */
+		public function setProperty(propertyName :String, value : Object) : void
+		{
+			properties[propertyName] = value;
+		}
+		
+		/**
+		 * Writes the properties name and associated values
+		 */
+		public function toString():String
+		{
+			var output : String = "";
+			for (var property : String in properties)
+			{
+				if (property != null && properties[property] != null)
+				{
+					if (property != gridSchedulingPlugin && property != localAllocPolicyPlugin && property != execTimeEstimationPlugin)
+						output += property + "=" + properties[property].toString().toLowerCase() + "\r\n";
+					else
+						output += property + "=" + properties[property].toString() + "\r\n";
+				}
+			}
+			return output;
+		} 
+		
+		public function clone() : ExperimentProperties
+		{
+			var exp : ExperimentProperties = new ExperimentProperties();
+			for (var property : String in properties)
+			{
+				exp.setProperty(property, properties[property]);
+			}
+			exp.metaname = metaname;
+			exp.name = name;
+			exp.resources = resources;
+			exp.runs = runs;
+			exp.topology = topology;
+			exp.workload = workload;
+			exp.global = global;
+			exp.local = local;
+			exp.exec = exec;
+			return exp;
+		}
+		
+		public function setWorkloadFile(file : String) : void
+		{
+			properties[workloadFile] = "input/workloads/" + file;
+			workload = file;
+		}
+	
+		public function setTopologyFile(file : String) : void
+		{
+			properties[networkTopologyFile] = "input/topologies/" + file;
+			topology = file;
+		}
+		
+		public function setResourceFile(file : String) : void
+		{
+			properties[resourceDescriptionFile] = "input/resources/" + file;
+			resources = file;
+		}
+		
+		public function setGlobal(item : Object) : void
+		{
+			properties[gridSchedulingPlugin] = item.data;
+			global = item.label;
+		}
+		
+		public function setLocal(item : Object) : void
+		{
+			properties[localAllocPolicyPlugin] = item.data;
+			local = item.label;
+		}
+		
+		public function setExec(item : Object) : void
+		{
+			properties[execTimeEstimationPlugin] = item.data;
+			exec = item.label;
+		}
+		
+		public function setRuns(runs : Number) : void
+		{
+			properties[numberOfSimulations] = runs;
+			this.runs = runs;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/FileProxy.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/FileProxy.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/FileProxy.as	(revision 15)
@@ -0,0 +1,85 @@
+package gssim.gssimstudio.editor.gssim.experiment
+{
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	import flash.net.FileReference;
+	import flash.utils.ByteArray;
+	
+	/**
+	 * Class for storing files.
+	 */
+	public class FileProxy extends EventDispatcher implements Proxy
+	{	
+		public static const CANCELLED : String = "(cancelled)";
+		
+		/**
+		 * File reference to picked file
+		 */
+		private var fref : FileReference;
+		
+		[Bindable]
+		public var filename : String;
+		[Bindable]
+		public var valid : Boolean;
+		
+		public var data : ByteArray;
+		
+		public function FileProxy(name : String = "")
+		{
+			this.filename = name;
+			//FIXME: maybe a better way to do this ?
+			if (name != "") valid = true;
+			else valid = false;
+		}
+
+		public override function toString() : String
+		{
+			return filename;
+		}
+		
+		/**
+		 * Load file using file reference browse() method
+		 */
+		public function LoadFile() : void
+		{
+			fref = new FileReference();
+			fref.addEventListener(Event.SELECT, selectHandler);
+			fref.addEventListener(Event.COMPLETE, completeHandler);
+			fref.addEventListener(Event.CANCEL, cancelHandler);
+			fref.browse();
+		}
+		
+		/**
+		 * File upload was cancelled
+		 */
+		private function cancelHandler(event:Event):void
+		{
+			filename = CANCELLED;
+			valid = false;
+			fref = null;
+			dispatchEvent(new Event(Event.COMPLETE));
+		}
+		
+		/**
+		 * User selected file from file browser - load it
+		 */
+		private function selectHandler(event:Event):void
+		{
+		    fref.load();
+		}
+		
+		/**
+		 * File upload was finished
+		 */
+		private function completeHandler(event:Event):void
+		{
+			filename = fref.name;
+			data = fref.data;
+			//clean reference to file (because data is already stored)
+			fref = null;
+			valid = true;
+			dispatchEvent(new Event(Event.COMPLETE));
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/Proxy.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/Proxy.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/experiment/Proxy.as	(revision 15)
@@ -0,0 +1,12 @@
+package gssim.gssimstudio.editor.gssim.experiment
+{
+	import flash.events.IEventDispatcher;
+	
+	/**
+	 * Interface for proxy
+	 */
+	public interface Proxy extends IEventDispatcher 
+	{
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/xml/XMLWrapper.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/xml/XMLWrapper.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/xml/XMLWrapper.as	(revision 15)
@@ -0,0 +1,17 @@
+package gssim.gssimstudio.editor.gssim.xml
+{
+	/**
+	 * Interface for XML based classes
+	 */
+	public interface XMLWrapper
+	{
+		/**
+		 * Returns formatted XML String with the content of class
+		 */
+		function toXMLString() : String;
+		/**
+		 * Returns the XML with the content of class
+		 */
+		function getXML(addLabel : Boolean) : XML;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/xml/XMLBasicWrapper.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/xml/XMLBasicWrapper.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/xml/XMLBasicWrapper.as	(revision 15)
@@ -0,0 +1,99 @@
+package gssim.gssimstudio.editor.gssim.xml
+{
+	import gssim.gssimstudio.editor.script.utils.DateTimeUtil;
+	
+	/**
+	 * Basic XML handling class 
+	 */
+	public class XMLBasicWrapper implements XMLWrapper
+	{
+		public function XMLBasicWrapper()
+		{
+		}
+
+		public function toXMLString():String
+		{
+			var xml : XML = getXML(false);
+			if (xml == null) throw Error("XML was not created!");
+			return xml.toXMLString();
+		}
+		
+		public function getXML(addLabel : Boolean):XML
+		{
+			return null;
+		}
+		
+		/**
+		 * Append given xml with text property
+		 */
+		protected function appendChildWithProperty(parent : XML, properties : Object, propertyName : String, required : Boolean, addLabel : Boolean) : XML
+		{
+			return appendChildWithText(parent, propertyName, properties[propertyName], required, addLabel);
+		}
+		
+		/**
+		 * Append given xml with text property
+		 */
+		protected function appendChildWithText(parent : XML, propertyName : String, propertyValue : Object, required : Boolean, addLabel : Boolean) : XML
+		{
+			if (propertyValue != null)
+			{
+				var xml : XML = XML(propertyName);
+				xml.appendChild(propertyValue);
+				if (addLabel) addStringAttribute(xml, "label", propertyName, false); 
+				parent.appendChild(xml);
+				
+			}
+			else if (required) throw Error("Missing required element: " + propertyName);
+			return parent;
+		}
+		
+		/**
+		 * Append given xml with the date value
+		 */
+		protected function appendChildWithDate(parent : XML, properties : Object, propertyName : String, required : Boolean, addLabel : Boolean) : XML
+		{
+			if (properties[propertyName] != null)
+			{
+				var xml : XML = XML(propertyName);
+				xml.appendChild(DateTimeUtil.convertFromDateToString(properties[propertyName]));
+				if (addLabel) addStringAttribute(xml, "label", propertyName, false); 
+				parent.appendChild(xml);
+				
+			}
+			else if (required) throw Error("Missing required element: " + propertyName);
+			return parent;
+		}
+		
+		/**
+		 * Append child with xml
+		 */
+		protected function appendChildWithXML(parent : XML, properties : Object, propertyName : String, required : Boolean, addLabel : Boolean) : XML
+		{
+			if (properties[propertyName] != null) parent.appendChild(properties[propertyName].getXML(addLabel));
+			else if (required) throw Error("Missing required element: " + propertyName);
+			return parent;
+		}
+		
+		/**
+		 * Add attribute from number to xml tag
+		 */
+		protected function addNumberAttribute(parent : XML, attributeName : String, value : Number, required : Boolean) : XML
+		{
+			if (!isNaN(value)) parent.@[attributeName] = value;
+			else if (required) throw Error("Missing required attribute: " + attributeName);
+			return parent;
+		}
+		
+		/**
+		 * Add attribute from string to xml tag
+		 */
+		protected function addStringAttribute(parent : XML, attributeName : String, value : String, required : Boolean) : XML
+		{
+			if (value != null && value != "") parent.@[attributeName] = value;
+			else if (required) throw Error("Missing required attribute: " + attributeName);
+			return parent;
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/file/workloadReader.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/file/workloadReader.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/file/workloadReader.as	(revision 15)
@@ -0,0 +1,152 @@
+package gssim.gssimstudio.editor.gssim.workload.file
+{
+	import flash.events.Event;
+	import flash.net.FileReference;
+	import flash.utils.ByteArray;
+	
+	import gssim.gssimstudio.editor.gssim.workload.ComputingResourceHostParameter;
+	import gssim.gssimstudio.editor.gssim.workload.Dist;
+	import gssim.gssimstudio.editor.gssim.workload.MultiDistribution;
+	import gssim.gssimstudio.editor.gssim.workload.PeriodicValidValues;
+	import gssim.gssimstudio.editor.gssim.workload.Preference;
+	import gssim.gssimstudio.editor.gssim.workload.PreferenceParameter;
+	import gssim.gssimstudio.editor.gssim.workload.RandParams;
+	import gssim.gssimstudio.editor.gssim.workload.WorkloadBasic;
+	
+	import gssim.gssimstudio.editor.script.utils.DateTimeUtil;
+	
+	import gssim.gssimstudio.editor.views.WorkloadEditor;
+	
+	/**
+	 * Loads workload configuration from file
+	 */
+	public class workloadReader
+	{
+		private var fref : FileReference;
+				
+		public function workloadReader()
+		{
+			fref = new FileReference();
+			fref.addEventListener(Event.SELECT, selectHandler);
+			fref.addEventListener(Event.COMPLETE, completeHandler);
+			fref.browse();
+		}
+		
+		public function selectHandler(event:Event):void
+		{
+		    fref.load();
+		}
+			
+		private function readRandParam(xml : XML) : RandParams
+		{
+			var params : RandParams = new RandParams("<" + xml.localName() + "/>");
+			//read attributes
+			for each (var paramName : XML in xml.attributes())
+			{
+				if (!isNaN(parseFloat(paramName)))
+					params.params.setProperty(paramName.name(), Number(paramName));
+				else
+					params.params.setProperty(paramName.name(), paramName);
+			}
+			if (xml.hasOwnProperty("MultiDistribution"))
+			{
+				params.multiDist = new MultiDistribution();
+				for each (var distXML : XML in xml.MultiDistribution.dist)
+				{
+					var dist : Dist = new Dist("");
+					//read attributes
+					for each (var distParamName : XML in distXML.attributes())
+					{
+						if (!isNaN(parseFloat(distParamName)))
+							dist.setProperty(distParamName.name(), Number(distParamName));
+						else
+							dist.setProperty(distParamName.name(), distParamName);
+					}
+					dist.Probability = Number(distXML);
+					params.multiDist.addDist(dist, dist.Probability); 
+				}
+			}
+			if (xml.hasOwnProperty("PeriodicValidValues"))
+			{
+				for each (var periodicXML : XML in xml.PeriodicValidValues)
+				{
+					var periodic : PeriodicValidValues = new PeriodicValidValues();
+					//read attributes
+					for each (var periodicParamName : XML in periodicXML.attributes())
+					{
+						if (!isNaN(parseFloat(periodicParamName)))
+							periodic.params.setProperty(periodicParamName.name(), Number(periodicParamName));
+						else
+							periodic.params.setProperty(periodicParamName.name(), periodicParamName);
+					}
+					if (periodicXML.hasOwnProperty("BeginValidTime")) periodic.BeginValidTime = DateTimeUtil.convertFromStringToDate(periodicXML.BeginValidTime.toString());
+					if (periodicXML.hasOwnProperty("EndValidTime")) periodic.EndValidTime = DateTimeUtil.convertFromStringToDate(periodicXML.EndValidTime.toString());
+					params.periodicValidValues.addItem(periodic);
+				}
+			}
+			return params;
+		}
+			
+		public function completeHandler(event:Event):void
+		{
+			var workload : WorkloadBasic = new WorkloadBasic();
+		    var data:ByteArray = fref.data;
+			
+			var xml : XML;
+			xml = XML(data.readUTFBytes(data.bytesAvailable));
+			
+			for (var i : Number = 0; i < xml.children().length(); i++)
+			{
+				var inner_xml : XML = xml.children()[i];
+				if (inner_xml.localName() == "SimulationStartTime")
+					workload.setProperty(WorkloadBasic.SimulationStartTime, DateTimeUtil.convertFromStringToDate(inner_xml.toString()));
+				else if (inner_xml.localName() == "SimulationTime")
+					workload.setProperty(WorkloadBasic.SimulationTime, inner_xml.toString());
+				else if (inner_xml.localName() == "ComputingResourceHostParameter")
+				{
+					var crhp : ComputingResourceHostParameter = new ComputingResourceHostParameter(inner_xml.@metric);
+					if (inner_xml.hasOwnProperty("value")) crhp.value = readRandParam(inner_xml.value[0]);
+					if (inner_xml.hasOwnProperty("range"))
+					{
+						if (inner_xml.range.hasOwnProperty("min")) crhp.range.min = readRandParam(inner_xml.range.min[0]);
+						if (inner_xml.range.hasOwnProperty("max")) crhp.range.max = readRandParam(inner_xml.range.max[0]);
+					}
+					workload.CRHP.addItem(crhp);
+				}
+				else if (inner_xml.localName() == "Preferences")
+				{
+					var pref : Preference = new Preference();
+					pref.preferenceType = inner_xml.@preferenceType;
+					for each (var paramXML : XML in inner_xml.parameter)
+					{
+						var param : PreferenceParameter = new PreferenceParameter();
+						param.Name = paramXML.name;
+						param.OptimizationType = paramXML.optimizationType;
+						if (paramXML.hasOwnProperty("endpoint")) param.Endpoint = paramXML.endpoint;
+						param.Importance = readRandParam(paramXML.importance[0]);
+						param.Value = readRandParam(paramXML.value[0]);
+						pref.preferenceParameters.addItem(param);
+					}
+					workload.Prefs.addItem(pref);
+				}
+				else if (inner_xml.localName() == "ExecutionTime")
+				{
+					for (var j : Number = 0; j < inner_xml.children().length(); j++)
+					{
+						var inner_inner_xml : XML = inner_xml.children()[j];
+						workload.setProperty("<"+inner_inner_xml.localName() + "/>", readRandParam(inner_inner_xml));
+					}
+				}
+				else
+				{
+					workload.setProperty("<"+inner_xml.localName() + "/>", readRandParam(inner_xml));
+				}
+			}
+			
+			fref = null;
+			
+			WorkloadEditor.workload = workload;
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/file/workloadWriter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/file/workloadWriter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/file/workloadWriter.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.editor.gssim.workload.file
+{
+	import flash.net.FileReference;
+	
+	import gssim.gssimstudio.editor.views.WorkloadEditor;
+	
+	/**
+	 * Writes workload configuration to file
+	 */
+	public class workloadWriter
+	{
+		private var fref : FileReference;
+		
+		public function workloadWriter()
+		{
+			//this doesnt work under IE
+			fref = new FileReference();
+			fref.save(WorkloadEditor.workload.getXML(false));
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/swf/WorkloadSWF.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/swf/WorkloadSWF.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/swf/WorkloadSWF.as	(revision 15)
@@ -0,0 +1,106 @@
+package gssim.gssimstudio.editor.gssim.workload.swf
+{
+	import flash.utils.ByteArray;
+	
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * Stores original SWF workload file with basic statistics
+	 */
+	public class WorkloadSWF
+	{
+		/**
+		 * Array with calculated statistics
+		 */
+		[Bindable]
+		public var statistics : ArrayCollection;
+		/**
+		 * Array with defined jobs
+		 */
+		[Bindable]
+		public var jobs : ArrayCollection;
+		/**
+		 * String containing headers of the file
+		 */
+		[Bindable]
+		public var headers : String;
+		
+		/**
+		 * This constructor takes data from ByteArray and converts to proper structure
+		 */
+		public function WorkloadSWF(dataFromFile : ByteArray = null)
+		{
+			jobs = new ArrayCollection();
+			statistics = new ArrayCollection();
+			headers = "";
+			
+			if (dataFromFile == null) return;
+
+			//analyze the file content			
+			var data:ByteArray = new ByteArray();
+			data.writeBytes(dataFromFile);
+			data.position = 0;
+		
+			//initialize statistics variables
+			var longestRun : Number = 0; // wait time + run time
+			var avgRunTime : Number = 0; // only run time
+			var maxReqTime : Number = 0; // maximum requested amount of proc time [s]
+			var maxReqMem : Number = 0; // maximum requested amount of memory [kb per proc]
+		
+			var array : Array;
+			//will this be the same on unix ?
+			array = data.readUTFBytes(data.bytesAvailable).split('\n');
+
+			for (var i : Number = 0; i < array.length; i++)
+			{
+				var line : String = array[i];
+				if (line == null) continue;
+				if (line.search(";") != -1)
+				{
+					headers += line.replace(";", "") + "\r";
+					continue;
+				}
+				var laror : Array = line.split(" ");
+				var lar : Array = new Array();
+				for (var k : Number = 0; k < laror.length; k++)
+				{
+					if (laror[k] != "") lar.push(laror[k]);
+				}
+				if (lar.length != 18) continue;
+				jobs.addItem(
+					{Field1 : Number(lar[0]),
+					Field2 : Number(lar[1]),
+					Field3 : Number(lar[2]),
+					Field4 : Number(lar[3]),
+					Field5 : Number(lar[4]),
+					Field6 : Number(lar[5]),
+					Field7 : Number(lar[6]),
+					Field8 : Number(lar[7]),
+					Field9 : Number(lar[8]),
+					Field10 : Number(lar[9]),
+					Field11 : Number(lar[10]),
+					Field12 : Number(lar[11]),
+					Field13 : Number(lar[12]),
+					Field14 : Number(lar[13]),
+					Field15 : Number(lar[14]),
+					Field16 : Number(lar[15]),
+					Field17 : Number(lar[16]),
+					Field18 : Number(lar[17])});
+				//calculate statistics
+				var obj : Object = jobs.getItemAt(jobs.length-1);
+				if (longestRun < obj.Field3 + obj.Field4) longestRun = obj.Field3 + obj.Field4;
+				if (maxReqMem < obj.Field10) maxReqMem = obj.Field10;
+				if (maxReqTime < obj.Field9) maxReqTime = obj.Field9;
+				avgRunTime += obj.Field4;
+			}
+			
+			//update statistics
+			statistics.addItem({name : "JobCount", value : jobs.length});
+			statistics.addItem({name : "LongestRun", value : longestRun});
+			statistics.addItem({name : "AvgRunTime", value : avgRunTime / jobs.length});
+			statistics.addItem({name : "MaxReqMem", value : maxReqMem});
+			statistics.addItem({name : "MaxReqTime", value : maxReqTime});
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/PeriodicValidValues.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/PeriodicValidValues.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/PeriodicValidValues.as	(revision 15)
@@ -0,0 +1,64 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Stores periodic valid values type, which has probabilistic parameters connected with
+	 * some time period during which they are valid
+	 */
+	public class PeriodicValidValues extends XMLBasicWrapper implements ValidableObject
+	{
+		private var properties : Object; // map id->value
+		
+		public var params : ParameterAttributes;
+		
+		public static const beginValidTime : String = "<BeginValidTime />";
+		public static const endValidTime : String = "<EndValidTime />";
+		
+		public function get BeginValidTime() : Date
+		{
+			return properties[beginValidTime];
+		}
+		public function set BeginValidTime(_value : Date) : void
+		{
+			properties[beginValidTime] = _value;
+		}
+		
+		public function get EndValidTime() : Date
+		{
+			return properties[endValidTime];
+		}
+		public function set EndValidTime(_value : Date) : void
+		{
+			properties[endValidTime] = _value;
+		}
+		
+		public function PeriodicValidValues()
+		{
+			properties = new Object();
+			properties[beginValidTime] = new Date();
+			properties[endValidTime] = new Date();
+			params = new ParameterAttributes("");
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <PeriodicValidValues />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			params.addParamsToTag(xml);
+			appendChildWithDate(xml, properties, beginValidTime, false, addLabel);
+			appendChildWithDate(xml, properties, endValidTime, false, addLabel);
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Preference.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Preference.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Preference.as	(revision 15)
@@ -0,0 +1,57 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing experiment preferences
+	 */
+	public class Preference extends XMLBasicWrapper implements ValidableObject
+	{
+		/**
+		 * Type of the preference
+		 */
+		[Bindable]
+		public var preferenceType : String;
+		/**
+		 * Collection of preference parameters included with this preference
+		 */
+		[Bindable]
+		public var preferenceParameters : ArrayCollection;
+		
+		public function Preference()
+		{
+			preferenceType = PreferenceType.PRIORITY;
+			preferenceParameters = new ArrayCollection();
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <Preferences />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "preferenceType", preferenceType, true);
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				xml.appendChild(param.getXML(addLabel));
+			}
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			var ae : AbstractError;
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				if (preferenceType == null) ac.addItem(new PreferenceError("MissingPreferenceTypeError", this));
+				for each (ae in param.validate()) ac.addItem(ae);
+			}
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/PreferenceParameter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/PreferenceParameter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/PreferenceParameter.as	(revision 15)
@@ -0,0 +1,99 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceParameterError;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Preference parameters are used in preference and describes more advanced options of preference
+	 */
+	public class PreferenceParameter extends XMLBasicWrapper implements ValidableObject
+	{
+		private var properties : Object; // map id->_value
+		
+		public static const name : String = "<name />";
+		public static const endpoint : String = "<endpoint />";
+		public static const importance : String = "<importance />";
+		public static const optimizationType : String = "<optimizationType />";
+		public static const value : String = "<value />";
+		
+		public function get Name() : String
+		{
+			return properties[name];
+		}
+		public function set Name(_value : String) : void
+		{
+			properties[name] = _value;
+		}
+		
+		public function get Endpoint() : String
+		{
+			return properties[endpoint];
+		}
+		public function set Endpoint(_value : String) : void
+		{
+			properties[endpoint] = _value;
+		}
+		
+		public function get Importance() : RandParams
+		{
+			return properties[importance];
+		}
+		public function set Importance(_value : RandParams) : void
+		{
+			properties[importance] = _value;
+		}
+		
+		public function get OptimizationType() : String
+		{
+			return properties[optimizationType];
+		}
+		public function set OptimizationType(_value : String) : void
+		{
+			properties[optimizationType] = _value;
+		}
+		
+		public function get Value() : RandParams
+		{
+			return properties[value];
+		}
+		public function set Value(_value : RandParams) : void
+		{
+			properties[value] = _value;
+		}
+		
+		public function PreferenceParameter()
+		{
+			properties = new Object();
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <parameter />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			appendChildWithProperty(xml, properties, name, true, addLabel);
+			appendChildWithProperty(xml, properties, endpoint, false, addLabel);
+			appendChildWithXML(xml, properties, importance, true, addLabel);
+			appendChildWithProperty(xml, properties, optimizationType, true, addLabel);
+			appendChildWithXML(xml, properties, value, true, addLabel);
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			var ae : AbstractError;
+			if (Name == null) ac.addItem(new PreferenceParameterError("MissingNameError", this));
+			if (Importance == null) ac.addItem(new PreferenceParameterError("MissingImportanceError", this));
+			else for each (ae in Importance.validate()) ac.addItem(ae);
+			if (OptimizationType == null) ac.addItem(new PreferenceParameterError("MissingOptimizationTypeError", this));
+			if (Value == null) ac.addItem(new PreferenceParameterError("MissingValueError", this));
+			else for each (ae in Value.validate()) ac.addItem(ae);
+			return ac;
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/PreferenceType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/PreferenceType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/PreferenceType.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.editor.gssim.workload.types
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * PreferenceType enum
+	 */
+	public final class PreferenceType
+	{
+		public static const PRIORITY : String = "PRIORITY";
+		public static const RANKING : String = "RANKING";
+		
+		public static function getAsArray() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			ac.addItem(PRIORITY);
+			ac.addItem(RANKING);
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/DistributionType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/DistributionType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/DistributionType.as	(revision 15)
@@ -0,0 +1,32 @@
+package gssim.gssimstudio.editor.gssim.workload.types
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * DistributionType enum
+	 */
+	public final class DistributionType
+	{
+		public static const CONSTANT : String = "constant"; 
+		public static const NORMAL : String = "normal"; 
+		public static const POISSON : String = "poisson"; 
+		public static const UNIFORM : String = "uniform"; 
+		public static const EXPONENTIAL : String = "exponential"; 
+		public static const GAMMA : String = "gamma"; 
+		public static const HARMONIC : String = "harmonic";
+		
+		public static function getAsArray() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			ac.addItem("");
+			ac.addItem(CONSTANT);
+			ac.addItem(NORMAL);
+			ac.addItem(POISSON);
+			ac.addItem(UNIFORM);
+			ac.addItem(EXPONENTIAL);
+			ac.addItem(GAMMA);
+			ac.addItem(HARMONIC);
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/Metric.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/Metric.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/Metric.as	(revision 15)
@@ -0,0 +1,49 @@
+package gssim.gssimstudio.editor.gssim.workload.types
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * Metric enum
+	 */
+	public final class Metric
+	{
+		public static const osname : String = "osname";
+		public static const ostype : String = "ostype";
+		public static const puarch : String = "puarch";
+		public static const osversion : String = "osversion";
+		public static const osrelease : String = "osrelease";
+		public static const memory : String = "memory";
+		public static const freememory : String = "freememory";
+		public static const cpucount : String = "cpucount";
+		public static const freecpus : String = "freecpus";
+		public static const cpuspeed : String = "cpuspeed";
+		public static const application : String = "application";
+		public static const diskspace : String = "diskspace";
+		public static const freediskspace : String = "freediskspace";
+		public static const remoteSubmissionInterface : String = "remoteSubmissionInterface";
+		public static const localResourceManager : String = "localResourceManager";
+		public static const hostname : String = "hostname";
+
+		public static function getAsArray() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			ac.addItem(osname);
+			ac.addItem(ostype);
+			ac.addItem(puarch);
+			ac.addItem(osversion);
+			ac.addItem(osrelease);
+			ac.addItem(memory);
+			ac.addItem(freememory);
+			ac.addItem(cpucount);
+			ac.addItem(freecpus);
+			ac.addItem(cpuspeed);
+			ac.addItem(application);
+			ac.addItem(diskspace);
+			ac.addItem(freediskspace);
+			ac.addItem(remoteSubmissionInterface);
+			ac.addItem(localResourceManager);
+			ac.addItem(hostname);
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/OptimizationType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/OptimizationType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/types/OptimizationType.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.editor.gssim.workload.types
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * OptimizationType enum
+	 */
+	public final class OptimizationType
+	{
+		public static const GAIN : String = "GAIN";
+		public static const COST : String = "COST";
+		
+		public static function getAsArray() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			ac.addItem(GAIN);
+			ac.addItem(COST);
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Dist.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Dist.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Dist.as	(revision 15)
@@ -0,0 +1,63 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * Class for storing distribution parts
+	 */
+	public final class Dist extends ParameterAttributes implements ValidableObject
+	{
+		public static const probability : String = "probability";
+		
+		public function get Probability() : Number
+		{
+			return properties[probability] as Number;
+		}
+		
+		public function set Probability(_value : Number) : void
+		{
+			properties[probability] = _value;
+		}
+		
+		public function Dist(parentTagName : String)
+		{
+			super(parentTagName);
+			tagName = <dist />;
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = super.getXML(addLabel);
+			xml.appendChild(Probability);
+			return xml;
+		}
+		
+		/**
+		 * Clone this Dist object to new instance
+		 */
+		public function clone() : Dist
+		{
+			var dist : Dist = new Dist(parentTagName);
+			dist.Avg = Avg;
+			dist.Distribution = Distribution;
+			dist.Expr = Expr;
+			dist.Id = Id;
+			dist.Max = Max;
+			dist.Min = Min;
+			dist.Probability = Probability;
+			dist.RefElementId = RefElementId;
+			dist.Seed = Seed;
+			dist.Stdev = Stdev;
+			return dist;
+		}
+		
+		public override function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/WorkloadBasic.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/WorkloadBasic.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/WorkloadBasic.as	(revision 15)
@@ -0,0 +1,271 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.ParametersError;
+	import gssim.gssimstudio.editor.gssim.errors.workload.RandParamsByTagError;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * Stores workload configuration properties
+	 */
+	public class WorkloadBasic extends XMLBasicWrapper implements ValidableObject
+	{
+		private var properties : Object; // map id->value
+		
+		/**
+		 * Defines start time of the simulation in human readable form. The value should be provided in xsd time format. See www.w3.org for details.
+		 * Example:
+ 		 * 		<SimulationStartTime>2009-01-15T10:00:00</SimulationStartTime>
+		 */
+		public static const SimulationStartTime : String = "<SimulationStartTime/>";
+
+		/**
+		 * Defines number of jobs to be generated. This element is used as an alternative for <SimulatonTime/>.
+		 * <JobCount/> is element of type RandParams.
+		 * Example shows how to create exactly 100 jobs:
+ 		 *		<JobCount avg="100" distribution="constant"/>
+ 		 */
+ 		public static const JobCount : String = "<JobCount/>";
+
+		/**
+		 * Defines length of the simulation. Generator will create number of jobs which can be executed in order during SimulationTime. The value should be provided in xsd duration format. See www.w3.org for details. This element is used as an alternative for <JobCount/>.
+		 */
+		 public static const SimulationTime : String = "<SimulationTime/>";
+		 
+		/**
+		 * Defines number of tasks in each job.
+		 * <TaskCount/> is element of type RandParams.
+		 * Example shows how to configure generator to create minimum 1 and maximum 10 tasks in each job. The average number of tasks in job will be 5, with standard deviation 3.0 and normal distribution.
+ 		 * 		<TaskCount avg="5" min="1" max="10" stdev="3.0" distribution="normal"/>
+ 		 */
+ 		 public static const TaskCount : String = "<TaskCount/>";
+
+		/**
+		 * Defines length of the task in number of instructions. This value will be translated to the seconds with assumption that task of this length will be executed on a single and the slowest processor. The minimum speed of the processor is fixed as a minimum value of cpuspeed host parameters from resource description. The resource description file is specified by resdesc parameter in *.properties file.
+		 * <TaskLength/> is element of type RandParams.
+		 * Example shows how to configure generator to create task of minimum 500 and maximum 1500 instructions. The average length of all tasks will be 1000 instructions with standard deviation 500.0 and normal distribution.
+ 		 * <TaskLength avg="1000" min="500" max="1500" stdev="500.0" distribution="normal"/>
+		 * The value of all fields in swf file expressed in seconds are calculated as division of task length in instructions and minimum speed of the single processor. If the minimum speed of the processor is 2, then the value of runtime field in swf file for task of length 764 instructions will be calculated as 764/2 = 382 seconds.
+		 */
+		 public static const TaskLength : String = "<TaskLength/>";
+
+		/**
+		 * Defines number of jobs which have the same submit time. Tasks which belongs to one job have always the same submit time. In swf file, submit time is interpreted as number of seconds after simulation start time.
+		 * <JobPackageLength/> is element of type RandParams.
+		 */
+		 public static const JobPackageLength : String = "<JobPackageLength/>";
+
+		/**
+		 * Defines time space between submission of successive jobs. In other words, this is the difference between submission time of two successive jobs. The value is expressed in seconds.
+		 * JobInterval is element of type RandParams.
+		 */
+		 public static const JobInterval : String = "<JobInterval/>";
+		 
+		 /**
+		 * Defines generator which creates <hostParameter/> element in task resource requirements section. See GrmsJobDescriptionSchema.xsd for detail description of task resource requirements.
+		 * This element requires attribute named: metric. The value of this attribute will be passed to task <hostParameter/> element as a value of its name attribute. The possible values of <hostParameter/> name attribute and thereby <ComputingResourceHostParameter/> metric attribute are: osname, ostype, puarch, osversion, osrelease, memory, freememory, cpucount, freecpus, cpuspeed, application, diskspace, freediskspace, remoteSubmissionInterface, localResourceManager, hostname. In simulation values of cpucount and memory host parameters are used by default. Others are currently ignored.
+		 * <ComputingResourceHostParameter/> is element of type RandParams.
+		 */
+		 public static const ComputingResourceHostParameters : String = "<ComputingResourceHostParameter/>";
+		
+		/**
+		 * This is the complex element, which was designed to describe section <preferences/> in task requirements. See GrmsJobDescriptionSchema.xsd for detail description of task resource requirements.
+		 * Element <preferences/> consist of list of <parameter/> elements. Each parameter must provide <name/>, <importance/>, <optimizationType/> and <value/> elements. <endpoint/> is optional. The values of these elements are passed to the attributes in parameter element in task resource requirements section. Name of the parameter elements and task parameter attributes are the same.
+		 * Workload generated only for simulation purpose does not require section <parameter/> in task resource requirements, therefore element <preferences/> my be skipped in xml workload configuration.
+		 * Importance and value are elements of type RandParams.
+		 */
+		 public static const Preferences : String = "<Preferences/>";
+
+		/**
+		 * This complex element was designed to describe <ExecutionTime/> section in task description. See GrmsJobDescriptionSchema.xsd for details.
+		 * <ExecutionTime/> consists of four child elements which have following interpretation:
+		 * 		<execDuration/> - describes user expectation about how long the task is. It differs from prior element <TaskLength/> which defines real length of the task. Value of this element is interpreted as number of instructions, and it will be translated into the seconds in the same way as <TaskLength/> is.
+		 * 		<periodStart/> - defines point in time from which task execution can be started. Value of this element is interpreted as number of seconds after <SimulationStartTime/>.
+		 * 		<periodEnd/> - defines point in time until task task execution must end. Value of this element is interpreted as number of seconds after <SimulationStartTime/>. It can be used as an alternative for <periodDuration/>.
+		 * 		<periodDuration/> - defines number of seconds after which task execution must end. This element can be used as an alternative for <periodEnd/>.
+		 * <execDuration/>, <periodStart/>, <periodEnd/> and <periodDuration/> are elements of type RandParams.
+		 * <ExecutionTime/> element is optional and it is not compulsory to use it in xml workload configuration. However, if advance reservation will be used, then <periodStart/> and <periodEnd/> (<periodDuration/>) are used as a begin and end time of the reservation.
+		 */
+		 private static const ExecutionTime : String = "<ExecutionTime/>";
+		 public static const ExecDuration : String = "<execDuration/>";
+		 public static const PeriodStart : String = "<periodStart/>";
+		 public static const PeriodEnd : String = "<periodEnd/>";
+		 public static const PeriodDuration : String = "<periodDuration/>";
+		
+		/**
+		 * Returns bindable array collection with stored CRHP
+		 */
+		public function get CRHP() : ArrayCollection
+		{
+			return properties[ComputingResourceHostParameters] as ArrayCollection;
+		}
+		
+		/**
+		 * Returns bindable array collection with stored preferences
+		 */
+		public function get Prefs() : ArrayCollection
+		{
+			return properties[Preferences] as ArrayCollection;
+		}
+		
+		public function WorkloadBasic()
+		{
+			properties = new Object();
+			properties[ComputingResourceHostParameters] = new ArrayCollection();
+			properties[Preferences] = new ArrayCollection();
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <WorkloadConfiguration />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			appendChildWithDate(xml, properties, SimulationStartTime, false, addLabel);
+			
+			//it's mandatory to fill one of these two fields, but not both
+			if (properties[JobCount] != null)
+			{
+				if (properties[SimulationTime] != null) throw Error("JobCount and SimulationTime cannot be set together!");
+				else appendChildWithXML(xml, properties, JobCount, true, addLabel);
+			}
+			else if (properties[SimulationTime] != null) appendChildWithProperty(xml, properties, SimulationTime, true, addLabel);
+			else throw Error("JobCount or SimulationTime must be set!");
+			
+			appendChildWithXML(xml, properties, TaskCount, true, addLabel);
+			appendChildWithXML(xml, properties, TaskLength, true, addLabel);
+			appendChildWithXML(xml, properties, JobPackageLength, true, addLabel);
+			appendChildWithXML(xml, properties, JobInterval, true, addLabel);
+			
+			for each (var crhp : ComputingResourceHostParameter in properties[ComputingResourceHostParameters])
+			{
+				xml.appendChild(crhp.getXML(addLabel));
+			}
+			
+			for each (var pp : Preference in properties[Preferences])
+			{
+				xml.appendChild(pp.getXML(addLabel));
+			}
+			
+			var xml_inner : XML = XML(ExecutionTime);
+			if (addLabel) addStringAttribute(xml_inner, "label", xml_inner.toXMLString(), false);
+			appendChildWithXML(xml_inner, properties, ExecDuration, false, addLabel);
+			appendChildWithXML(xml_inner, properties, PeriodStart, false, addLabel);
+			//one cannot declare both fields
+			if (properties[PeriodEnd] != null)
+			{
+				if (properties[PeriodDuration] != null) throw Error("PeriodEnd and PeriodDuration cannot be set together!");
+				else appendChildWithXML(xml_inner, properties, PeriodEnd, false, addLabel);
+			}
+			else appendChildWithXML(xml_inner, properties, PeriodDuration, false, addLabel);
+			
+			if (xml_inner.children().length() != 0) xml.appendChild(xml_inner);
+			
+			//for debug only
+			//trace(xml.toXMLString());
+			return xml;
+		}
+
+		/**
+		 * Returns property value given by name
+		 */
+		public function getProperty(propertyName :String) : Object
+		{
+			return properties[propertyName];
+		}
+		
+		/**
+		 * Sets property value given by name
+		 */
+		public function setProperty(propertyName :String, value : Object) : void
+		{
+			properties[propertyName] = value;
+		}
+		
+		/**
+		 * Returns simulation start time property as Date
+		 */
+		public function get getSimulationStartTime() : Date
+		{
+			return properties[SimulationStartTime] as Date;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			var ae : AbstractError;
+			if (properties[JobCount] != null)
+			{
+				if (properties[SimulationTime] != null)
+					ac.addItem(new AbstractError("CannotBeSetTogetherError", "JobCount, SimulationTime"));
+				else
+					for each (ae in properties[JobCount].validate()) ac.addItem(ae);
+			}
+			else if (properties[SimulationTime] == null) ac.addItem(new AbstractError("OneMustBeSetError", "JobCount, SimulationTime"));
+			if (properties[JobInterval] == null) ac.addItem(new RandParamsByTagError("MissingError", JobInterval));
+			else for each (ae in properties[JobInterval].validate()) ac.addItem(ae);
+			if (properties[JobPackageLength] == null) ac.addItem(new RandParamsByTagError("MissingError", JobPackageLength));
+			else for each (ae in properties[JobPackageLength].validate()) ac.addItem(ae);
+			if (properties[TaskCount] == null) ac.addItem(new RandParamsByTagError("MissingError", TaskCount));
+			else for each (ae in properties[TaskCount].validate()) ac.addItem(ae);
+			if (properties[TaskLength] == null) ac.addItem(new RandParamsByTagError("MissingError", TaskLength));
+			else for each (ae in properties[TaskLength].validate()) ac.addItem(ae);
+			
+			for each (var pp : Preference in properties[Preferences])
+			{
+				for each (ae in pp.validate()) ac.addItem(ae);
+			}
+			
+			//one cannot declare both fields
+			if (properties[PeriodEnd] != null)
+			{
+				if (properties[PeriodDuration] != null) ac.addItem(new AbstractError("CannotBeSetTogetherError", "PeriodEnd, PeriodDuration"));
+			}
+			
+			if (properties[ExecDuration] != null) for each (ae in properties[ExecDuration].validate()) ac.addItem(ae);
+			if (properties[PeriodStart] != null) for each (ae in properties[PeriodStart].validate()) ac.addItem(ae);
+			if (properties[PeriodEnd] != null) for each (ae in properties[PeriodEnd].validate()) ac.addItem(ae);
+			if (properties[PeriodDuration] != null) for each (ae in properties[PeriodDuration].validate()) ac.addItem(ae);
+			
+			//check for reference id errors
+			var referencing : ArrayCollection = new ArrayCollection();
+			var listOfIds : ArrayCollection = new ArrayCollection();
+			for each (var rand : Object in properties)
+			{
+				if (rand is RandParams)
+				{
+					addToLists(listOfIds, referencing, rand as RandParams, ac);
+				}
+			}
+			for each (var cpar : ComputingResourceHostParameter in CRHP)
+			{
+				addToLists(listOfIds, referencing, cpar.value, ac);
+				addToLists(listOfIds, referencing, cpar.range.min, ac);
+				addToLists(listOfIds, referencing, cpar.range.max, ac);
+			}
+			for each (var r : RandParams in referencing)
+			{
+				if (!listOfIds.contains(r.params.RefElementId)) ac.addItem(new ParametersError("UnknownReferenceError", r.params));
+				else if (r.params.RefElementId == r.params.Id) ac.addItem(new ParametersError("SelfReferenceError", r.params));
+				//TODO: detect complex cycle references
+			}
+			
+			return ac;
+		}
+		
+		/**
+		 * Add given id to lists for id reference errors validation
+		 */
+		private function addToLists(ids : ArrayCollection, refs : ArrayCollection, rand : RandParams, errorList : ArrayCollection) : void
+		{
+			if (rand == null) return;
+			if (rand.params.Id != null && rand.params.Id != "")
+			{
+				if (ids.contains(rand.params.Id)) errorList.addItem(new ParametersError("DoubleIDError", rand.params));
+				else ids.addItem(rand.params.Id);
+			}
+			if (rand.params.RefElementId != null && rand.params.RefElementId != "") refs.addItem(rand);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/ParameterAttributes.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/ParameterAttributes.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/ParameterAttributes.as	(revision 15)
@@ -0,0 +1,180 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.workload.types.DistributionType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * Stores basic probabilistic parameters
+	 */
+	public class ParameterAttributes extends XMLBasicWrapper implements ValidableObject
+	{
+		[Bindable]
+		public var parentTagName : String = "";
+		
+		protected var tagName : XML = <value />;
+		
+		protected var properties : Object; // map id->value
+		
+		public static const id : String = "id";
+		public static const refElementId : String = "refElementId";
+		public static const expr : String = "expr";
+		public static const avg : String = "avg";
+		public static const stdev : String = "stdev";
+		public static const min : String = "min";
+		public static const max : String = "max";
+		public static const seed : String = "seed";
+		public static const distribution : String = "distribution";
+		
+		public function get Id() : String
+		{
+			return properties[id];
+		}
+		public function set Id(_value : String) : void
+		{
+			properties[id] = _value;
+		}
+
+		public function get RefElementId() : String
+		{
+			return properties[refElementId];
+		}
+		
+		public function set RefElementId(_value : String) : void
+		{
+			properties[refElementId] = _value;
+		}
+		
+		public function get Expr() : String
+		{
+			return properties[expr];
+		}
+		
+		public function set Expr(_value : String) : void
+		{
+			properties[expr] = _value;
+		}
+		
+		public function get Avg() : Number
+		{
+			return properties[avg] as Number;
+		}
+		
+		public function set Avg(_value : Number) : void
+		{
+			properties[avg] = _value;
+		}
+		
+		public function get Stdev() : Number
+		{
+			return properties[stdev] as Number;
+		}
+		
+		public function set Stdev(_value : Number) : void
+		{
+			properties[stdev] = _value;
+		}
+		
+		public function get Min() : Number
+		{
+			return properties[min] as Number;
+		}
+		
+		public function set Min(_value : Number) : void
+		{
+			properties[min] = _value;
+		}
+		
+		public function get Max() : Number
+		{
+			return properties[max] as Number;
+		}
+		
+		public function set Max(_value : Number) : void
+		{
+			properties[max] = _value;
+		}
+		
+		public function get Seed() : Number
+		{
+			return properties[seed] as Number;
+		}
+		
+		public function set Seed(_value : Number) : void
+		{
+			properties[seed] = _value;
+		}
+		
+		public function get Distribution() : String
+		{
+			return properties[distribution];
+		}
+		
+		public function set Distribution(_value : String) : void
+		{
+			properties[distribution] = _value;
+		}
+		
+		/**
+		 * Returns property value given by name
+		 */
+		public function getProperty(propertyName : String) : Object
+		{
+			return properties[propertyName];
+		}
+		
+		/**
+		 * Sets property value given by name
+		 */
+		public function setProperty(propertyName : String, _value : Object) : void
+		{
+			properties[propertyName] = _value;
+		}
+		
+		public function ParameterAttributes(parentTagName : String)
+		{
+			properties = new Object();
+			Avg = NaN;
+			Min = NaN;
+			Max = NaN;
+			Seed = NaN;
+			Stdev = 1;
+			Distribution = DistributionType.CONSTANT;
+			this.parentTagName = parentTagName;
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = tagName.copy();
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addParamsToTag(xml);
+			return xml;			
+		}
+
+		/**
+		 * Add all properties as attributes to given XML tag
+		 */
+		public function addParamsToTag(xml : XML) : XML
+		{
+			addStringAttribute(xml, "id", Id, false);
+			addStringAttribute(xml, "refElementId", RefElementId, false);
+			addStringAttribute(xml, "expr", Expr, false);
+			addNumberAttribute(xml, "avg", Avg, false);
+			addNumberAttribute(xml, "stdev", Stdev, false);
+			addNumberAttribute(xml, "min", Min, false);
+			addNumberAttribute(xml, "max", Max, false);
+			addNumberAttribute(xml, "seed", Seed, false);
+			addStringAttribute(xml, "distribution", Distribution, false);
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/RandParams.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/RandParams.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/RandParams.as	(revision 15)
@@ -0,0 +1,53 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.ExistingRandParamsError;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Basic value type, described by probabilistic parameters, periodic valid values and multi-distribution
+	 */
+	public class RandParams extends XMLBasicWrapper implements ValidableObject
+	{
+		private var tagName : XML = <RandParams />;
+		
+		[Bindable]
+		public var params : ParameterAttributes;
+		
+		[Bindable]
+		public var periodicValidValues : ArrayCollection;
+		
+		public var multiDist : MultiDistribution;
+		
+		public function RandParams(tagName : String)
+		{
+			params = new ParameterAttributes(tagName);
+			this.tagName = XML(tagName);
+			periodicValidValues = new ArrayCollection();
+		}
+
+		public override function getXML(addLabel : Boolean):XML
+		{
+			var xml : XML = tagName.copy();
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			if (periodicValidValues.length != 0 && multiDist != null) throw Error("PeriodicValidValues and MultiDistribution cannot be set together!");
+			for each (var periodic : PeriodicValidValues in periodicValidValues)
+			{
+				xml.appendChild(periodic.getXML(addLabel));
+			}
+			if (multiDist != null) xml.appendChild(multiDist.getXML(addLabel));
+			if (params != null) params.addParamsToTag(xml);
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			if (periodicValidValues.length != 0 && multiDist != null) ac.addItem(new ExistingRandParamsError("CannotBeSetTogetherError", "PeriodicValidValues, MultiDistribution", this));
+			return ac;
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/MultiDistribution.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/MultiDistribution.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/MultiDistribution.as	(revision 15)
@@ -0,0 +1,89 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class describing multi-distribution value
+	 */
+	public class MultiDistribution extends XMLBasicWrapper implements ValidableObject
+	{
+		private var distributions : ArrayCollection;
+		
+		public function get Distributions() : ArrayCollection
+		{
+			return distributions;
+		}
+		
+		public function MultiDistribution()
+		{
+			distributions = new ArrayCollection();
+		}
+
+		/**
+		 * Add new partial distribution
+		 */
+		public function addDist(dist : Dist, prob : Number) : void
+		{
+			dist.Probability = prob;
+			distributions.addItem(dist);
+		}
+		
+		/**
+		 * Remove distribution at given index
+		 */
+		public function removeDist(distIndex : Number) : void
+		{
+			distributions.removeItemAt(distIndex);
+		}
+		
+		/**
+		 * Get distribution at given index
+		 */
+		public function getDist(distIndex : Number) : Dist
+		{
+			return distributions.getItemAt(distIndex) as Dist;
+		}
+		
+		/**
+		 * Update distribution at given index with probability value
+		 */
+		public function updateDist(distIndex : Number, prob : Number) : void
+		{
+			distributions.getItemAt(distIndex).Probability = prob;
+		}
+
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <MultiDistribution />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			for each (var dist : Dist in distributions)
+			{
+				xml.appendChild(dist.getXML(addLabel));
+			}
+			return xml;
+		}
+		
+		/**
+		 * Clone this multi-distribution object
+		 */
+		public function clone() : MultiDistribution
+		{
+			var multi : MultiDistribution = new MultiDistribution();
+			for each (var dist : Dist in distributions)
+			{
+				multi.addDist(dist.clone(), dist.Probability);
+			}
+			return multi;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/ComputingResourceHostParameter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/ComputingResourceHostParameter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/ComputingResourceHostParameter.as	(revision 15)
@@ -0,0 +1,44 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Consists of metric, value and optionally a range. Used to define dependant values
+	 */
+	public class ComputingResourceHostParameter extends XMLBasicWrapper implements ValidableObject
+	{
+		[Bindable]
+		public var metric : String;
+		[Bindable]
+		public var value : RandParams;
+		public var range : Range;
+		
+		public function ComputingResourceHostParameter(metric : String)
+		{
+			this.metric = metric;
+			value = new RandParams("<value />");
+			range = new Range();
+		}
+
+		public override function getXML(addLabel : Boolean):XML
+		{
+			var xml : XML = <ComputingResourceHostParameter />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "metric", metric, true);
+			if (value != null) xml.appendChild(value.getXML(addLabel));
+			var rangeXML : XML = range.getXML(addLabel);
+			if (rangeXML != null) xml.appendChild(rangeXML);
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Range.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Range.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/workload/Range.as	(revision 15)
@@ -0,0 +1,33 @@
+package gssim.gssimstudio.editor.gssim.workload
+{
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Consists of minimum and maximum value
+	 */
+	public class Range extends XMLBasicWrapper implements ValidableObject
+	{
+		public var min : RandParams;
+		public var max : RandParams;
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			if (min == null && max == null) return null;
+			var xml : XML = <range />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			if (min != null) xml.appendChild(min.getXML(addLabel));
+			if (max != null) xml.appendChild(max.getXML(addLabel));
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			
+			return ac;
+		}		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/WindowManager.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/WindowManager.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/WindowManager.as	(revision 15)
@@ -0,0 +1,72 @@
+package gssim.gssimstudio.editor.gssim
+{
+	import flash.events.Event;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	import flexlib.mdi.containers.MDIWindow;
+	import flexlib.mdi.events.MDIManagerEvent;
+	
+	import mx.controls.Alert;
+	import mx.controls.TextArea;
+	import mx.events.CloseEvent;
+	
+	/**
+	 * Helps handle windows on MDICanvas
+	 */
+	public class WindowManager
+	{
+		private var mdiCanvas : MDICanvas;
+		private var eventMonitor:TextArea;
+		private var queuedEvent:MDIManagerEvent;
+		private var _confirmClose :Boolean = false;
+		public function get confirmClose() : Boolean
+		{
+			return _confirmClose;
+		}
+		public function set confirmClose(value: Boolean):void
+		{
+			_confirmClose = value;
+		}
+		
+		
+		public function WindowManager(canvas : MDICanvas)
+		{
+			// create textfield
+			eventMonitor = new TextArea();
+			eventMonitor.percentWidth = 100;
+			eventMonitor.height = 150;
+			
+			mdiCanvas = canvas;
+					
+			//listen for all window events
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_ADD, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_MINIMIZE, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESTORE, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_MAXIMIZE, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_CLOSE, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_FOCUS_START, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_FOCUS_END, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_DRAG_START, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_DRAG, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_DRAG_END, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESIZE_START, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESIZE, windowEventHandler);
+			mdiCanvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESIZE_END, windowEventHandler);
+		}
+		
+		// default event handler
+		private function windowEventHandler(event:Event):void
+		{
+			if(event is MDIManagerEvent)
+			{
+				var mgrEvent:MDIManagerEvent = event as MDIManagerEvent;
+				if(eventMonitor.parent != null)
+				{
+					eventMonitor.text += mgrEvent.window.title + ": " + event.type + "\n";
+					eventMonitor.verticalScrollPosition = eventMonitor.maxVerticalScrollPosition;
+					eventMonitor.validateNow();
+				}
+			}
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/MultiImageContainer.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/MultiImageContainer.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/MultiImageContainer.mxml	(revision 15)
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
+				   xmlns:s="library://ns.adobe.com/flex/spark" 
+				   xmlns:mx="library://ns.adobe.com/flex/mx"
+				   creationComplete="init()">
+	<fx:Declarations>
+		<!-- Place non-visual elements (e.g., services, value objects) here -->
+	</fx:Declarations>
+	<fx:Script>
+		<![CDATA[
+			import mx.collections.ArrayCollection;
+			import mx.controls.Image;
+			import mx.core.Container;
+			
+			import spark.components.HScrollBar;
+			import spark.components.VScrollBar;
+			
+			private var images : ArrayCollection = new ArrayCollection();
+			
+			public function get gallery() : ArrayCollection
+			{
+				return images;
+			}
+			
+			private const ZOOM_STEP : Number = 5/6;
+			private const MAX_ZOOM : Number = 2;
+			private const MIN_ZOOM : Number = 0.1;
+			
+			private function init() : void
+			{
+				//this.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelEventHandler);
+				var hScrollbar : HScrollBar = new HScrollBar();
+				hScrollbar.viewport = this;
+				var vScrollbar : VScrollBar = new VScrollBar();
+				vScrollbar.viewport = this;
+			}
+			
+			public override function get width() : Number
+			{
+				var max : Number = 0;
+				for each (var img : Image in images)
+				{
+					if (max < img.x + img.width) max = img.x + img.width;
+				}
+				return max;
+			}
+			
+			public override function get height() : Number
+			{
+				var max : Number = 0;
+				for each (var img : Image in images)
+				{
+					if (max < img.y + img.height) max = img.y + img.height;
+				}
+				return max;
+			}
+			
+			public function addImage(img : Image) : void
+			{
+				images.addItem(img);
+				this.addElement(img);
+			}
+			
+			public function removeImage(img : Image) : void
+			{
+				this.removeElement(img);
+				for (var i : Number; i < images.length; i++)
+				{
+					if (images[i] == img) break;
+				}
+				images.removeItemAt(i);
+			}
+			
+			public function scroll(x : Number, y : Number) : void
+			{
+				var container : Container = parent as Container;
+				container.horizontalScrollPosition = x;
+				container.verticalScrollPosition = y;
+			}
+			
+		]]>
+	</fx:Script>
+</s:Group>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/QuickTooltipImage.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/QuickTooltipImage.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/QuickTooltipImage.as	(revision 15)
@@ -0,0 +1,27 @@
+package gssim.gssimstudio.editor.gssim.components
+{
+	import flash.events.MouseEvent;
+	
+	import mx.controls.Image;
+	import mx.managers.ToolTipManager;
+	
+	public class QuickTooltipImage extends Image
+	{
+		public function QuickTooltipImage()
+		{
+			super();
+			addEventListener(MouseEvent.MOUSE_OVER, mouseOverEventHandler);
+			addEventListener(MouseEvent.MOUSE_OUT, mouseOutEventHandler);
+		}
+		
+		private function mouseOverEventHandler(event : MouseEvent) : void
+		{
+			ToolTipManager.showDelay = 0;
+		}
+		
+		private function mouseOutEventHandler(event : MouseEvent) : void
+		{
+			ToolTipManager.showDelay = 500;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CameleonLabel.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CameleonLabel.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CameleonLabel.mxml	(revision 15)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<s:Label xmlns:fx="http://ns.adobe.com/mxml/2009" 
+		 xmlns:s="library://ns.adobe.com/flex/spark" 
+		 xmlns:mx="library://ns.adobe.com/flex/mx"
+		 color="{selectedColor}">
+	<fx:Script>
+		<![CDATA[
+			[Bindable]
+			public var selectedColor : Number;
+		]]>
+	</fx:Script>
+</s:Label>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/RollOutMenu.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/RollOutMenu.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/RollOutMenu.mxml	(revision 15)
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="0" height="0" creationComplete="init()">
+	<mx:Metadata>
+        [DefaultProperty("children")]
+    </mx:Metadata>
+	<mx:Script>
+		<![CDATA[
+			import com.greensock.TweenLite;
+			
+			import gssim.gssimstudio.editor.flare.util.Property;
+			
+			import gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin;
+			
+			import mx.binding.utils.BindingUtils;
+			import mx.core.UIComponent;
+			import mx.effects.Fade;
+			import mx.resources.IResourceManager;
+			
+			import spark.skins.spark.ToggleButtonSkin;
+			
+			private var _children:Array = [];
+            private var _childrenChanged:Boolean = false;
+			
+			//autohide menu timer
+			public  var appTimer:Timer = new Timer(3000, 0); 
+			
+			protected function init() : void
+			{
+				/*
+				if (hideOnRollIn)
+				{
+					var closeButton : IconToggleButton= new IconToggleButton();
+					closeButton.width = buttonWidth;
+					closeButton.height = buttonHeight;
+					closeButton.setStyle("skinClass", Class(IconToggleButtonSkin));
+					closeButton.addEventListener(MouseEvent.CLICK, genericButtonClick);
+					closeButton.setStyle("showEffect", fade);
+					closeButton.setStyle("hideEffect", fade);
+					closeButton.setStyle("iconUp", "assets/deleteButton.png");
+					BindingUtils.bindProperty(closeButton, "label", resourceManager, 
+						{
+							name: "getString", 
+							getter: function(resMan:IResourceManager):String { 
+								return resMan.getString("TopologyEditor", "Open");}
+						});
+					menuButtons.addChild(closeButton);
+				}
+				*/
+				(menuButtons.getChildAt(0) as IconToggleButton).selected = true;
+				rollIn(false);
+				if (!selectable) (menuButtons.getChildAt(0) as IconToggleButton).selected = false;
+				
+				for each (var button : IconToggleButton in menuButtons.getChildren())
+				{
+					if (button.menu != null)
+					{
+						BindingUtils.bindProperty(button, "label", button.menu, "menuLabel");
+						button.setStyle("iconUp", menuIcon);
+					}
+				}
+				
+				this.appTimer.addEventListener("timer", this.timerHandler);  
+				this.appTimer.start(); 
+			}
+			
+			public function timerHandler(event:TimerEvent):void {
+				// when the timer fires its event hide the toolbar
+				rollIn();
+				isRolledOut = false;
+			}
+			
+			public function onMouseMove(event:MouseEvent):void {
+				//whenever the mouse moves over the application, show the
+				// toolbar and restart the timer restart the timer
+				this.appTimer.reset();
+				this.appTimer.start();
+			}
+			
+            public function set children( value:* ):void
+            {
+                if( value is DisplayObject )
+                    _children = [ value ];
+                else
+                    _children = value;
+                
+                _childrenChanged = true;
+                invalidateProperties();
+            }
+            
+            public function get children():Array
+            {
+                return _children;
+            }
+            
+            protected override function commitProperties():void
+            {
+                super.commitProperties();
+                
+                if( _childrenChanged )
+                {
+                    for each( var child:DisplayObject in _children )
+                    {
+                    	if (!(child is IconToggleButton) && !(child is RollOutMenu)) throw Error("Illegal UIComponent - only buttons are allowed!");
+						var button : IconToggleButton;
+						if (child is IconToggleButton)
+						{
+	                    	button = child as IconToggleButton; 
+	                        menuButtons.addChild( button );
+							button.addEventListener(MouseEvent.CLICK, genericButtonClick);
+	                        button.setStyle("showEffect", fade);
+	                        button.setStyle("hideEffect", fade);
+							button.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
+						}
+						else
+						{
+							var menu : RollOutMenu = child as RollOutMenu;
+							button = new IconToggleButton();
+							button.width = buttonWidth;
+							button.height = buttonHeight;
+							button.setStyle("skinClass", Class(IconToggleButtonSkin));
+							button.addEventListener(MouseEvent.CLICK, genericButtonClick);
+							button.setStyle("showEffect", fade);
+							button.setStyle("hideEffect", fade);
+							button.addEventListener(MouseEvent.CLICK, rollMenu);
+							button.menu = menu;
+							menuButtons.addChild(button);
+							parentMenu.addChild(menu);
+							menu.visible = false;
+							menu.includeInLayout = false;
+							menu.hideOnRollIn = true;
+							menu.setStyle("showEffect", fade);
+							menu.setStyle("hideEffect", fade);
+						}
+                    }
+                }    
+            }
+			
+			private function rollMenu(event : Event) : void
+			{
+				var picked : RollOutMenu = (event.target as IconToggleButton).menu;
+				for each (var comp : UIComponent in parentMenu.getChildren())
+				{
+					if (comp is RollOutMenu)
+					{
+						var menu : RollOutMenu = comp as RollOutMenu;
+						if (menu == picked)
+						{
+							menu.visible = true;
+							menu.rollOutManually();
+						}
+						else
+						{
+							menu.rollInManually();
+							menu.visible = false;
+						}
+					}
+				}
+			}
+			
+			[Bindable]
+			public var menuLabel : String;
+			[Bindable]
+			public var menuIcon : String;
+			
+			private var isRolledOut : Boolean;
+			
+			public var selectable : Boolean;
+			
+			protected var hideOnRollIn : Boolean;
+			
+			public var buttonWidth : Number = 128;
+			public var buttonHeight : Number = 64;
+			
+			public function get selected() : IconToggleButton
+			{
+				for each (var button : IconToggleButton in menuButtons.getChildren())
+				{
+					if (button.selected) return button;
+				}
+				return null;
+			}
+			
+			public function set selected(_button : IconToggleButton) : void
+			{
+				if (_button == null) (menuButtons.getChildAt(0) as IconToggleButton).selected = true;
+				else 
+				for each (var button : IconToggleButton in menuButtons.getChildren())
+				{
+					if (button == _button) button.selected = true;
+					else button.selected = false;
+				}
+				rollIn(false);
+				isRolledOut = false;
+			}
+			
+			public function rollOutManually(animate : Boolean = true) : void
+			{
+				this.appTimer.reset();
+				this.appTimer.start();
+				var yPosition : Number = 0;
+				for each (var button : IconToggleButton in menuButtons.getChildren())
+				{
+					button.selected = false;
+					button.visible = true;
+					if (animate) TweenLite.to(button, 0.25, {y : yPosition});
+					else button.y = yPosition;
+					yPosition += button.height;
+				}
+				isRolledOut = true;
+			}
+			
+			public function rollInManually(animate : Boolean = true) : void
+			{
+				var firstButton : IconToggleButton = menuButtons.getChildAt(0) as IconToggleButton;
+				var yPosition : Number = 0;
+				for each (var button : IconToggleButton in menuButtons.getChildren())
+				{
+					button.selected = false;
+					if (!hideOnRollIn && button == firstButton) button.selected = true; 
+					button.visible = true;
+					if (animate) TweenLite.to(button, 0.25, {y : yPosition});
+					else button.y = yPosition;
+					yPosition += button.height;
+				}
+				isRolledOut = false;
+			}
+			
+			private function rollOut(animate : Boolean = true) : void
+			{
+				this.appTimer.reset();
+				this.appTimer.start();
+				var yPosition : Number = 0;
+				for each (var button : IconToggleButton in menuButtons.getChildren())
+				{
+					if (animate) TweenLite.to(button, 0.25, {y : yPosition});
+					else button.y = yPosition;
+					yPosition += button.height;
+				}
+			}
+			
+			private function rollIn(animate : Boolean = true) : void
+			{
+				if (!hideOnRollIn) (menuButtons.getChildAt(0) as IconToggleButton).selected = true;
+				for each (var button : IconToggleButton in menuButtons.getChildren())
+				{
+					if (animate) TweenLite.to(button, 0.25, {y : 0});
+					else button.y = 0;
+					//this fixes bug with fade animation
+					if (!animate)
+					{
+						button.clearStyle("showEffect");
+                    	button.clearStyle("hideEffect");
+					}
+					if (!button.selected) button.visible = false;
+					else button.visible = true;
+					//this fixes bug with fade animation
+					if (!animate)
+					{
+						button.setStyle("showEffect", fade);
+                		button.setStyle("hideEffect", fade);
+					}
+				}
+				if (hideOnRollIn)
+				{
+					visible = false;
+					includeInLayout = false;
+				}
+				else
+				{
+					(menuButtons.getChildAt(0) as IconToggleButton).selected = false;
+				}
+			}
+			
+			private function genericButtonClick(event : Event) : void
+			{
+				for each (var button : IconToggleButton in menuButtons.getChildren())
+				{
+					button.selected = false;
+					button.visible = true;
+				}
+				if (selectable) event.target.selected = true;
+				else (menuButtons.getChildAt(0) as IconToggleButton).selected = true;
+				if (isRolledOut) rollIn();
+				else rollOut();
+				if (!selectable) (menuButtons.getChildAt(0) as IconToggleButton).selected = false;
+				isRolledOut = !isRolledOut;
+			}
+			
+		]]>
+	</mx:Script>
+	
+	<mx:Fade duration="200" id="fade"/>
+	
+	<mx:HBox id="parentMenu" horizontalGap="0">
+	<mx:VBox id="menuButtons" verticalGap="0" />
+	</mx:HBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CheckADGRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CheckADGRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CheckADGRenderer.as	(revision 15)
@@ -0,0 +1,283 @@
+package gssim.gssimstudio.editor.gssim.components
+{
+	import flash.events.MouseEvent;
+	import flash.xml.*;
+	
+	import mx.collections.*;
+	import mx.controls.AdvancedDataGrid;
+	import mx.controls.CheckBox;
+	import mx.controls.Image;
+	import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
+	import mx.controls.advancedDataGridClasses.AdvancedDataGridGroupItemRenderer;
+	import mx.controls.advancedDataGridClasses.AdvancedDataGridListData;
+	import mx.controls.listClasses.*;
+	import mx.core.mx_internal;
+	use namespace mx_internal; 
+	
+
+	public class CheckADGRenderer extends AdvancedDataGridGroupItemRenderer
+	{
+        protected var myImage:Image;
+        
+        // set image properties
+        private var imageWidth:Number 	= 6;
+	    private var imageHeight:Number 	= 6;
+        private var inner:String 	= "assets/inner.png";
+		protected var myCheckBox:CheckBox;
+		static private var STATE_SCHRODINGER:String = "schrodinger";
+		static private var STATE_CHECKED:String = "checked";
+		static private var STATE_UNCHECKED:String = "unchecked";
+	    
+        public function CheckADGRenderer () 
+		{
+			super();
+			mouseEnabled = false;
+		}
+		private function toggleParents (item:Object, adg:AdvancedDataGrid, state:String):void
+		{
+			if (item == null)
+			{
+				return;
+			}
+			else
+			{
+				item.@state = state;
+				toggleParents(adg.getParentItem(item), adg, getState (adg, adg.getParentItem(item)));
+			}
+		}
+		
+		private function toggleChildren (item:Object, adg:AdvancedDataGrid, state:String):void
+		{
+			if (item == null)
+			{
+				return;
+			}
+			else
+			{
+				item.@state = state;
+				var adgCollection:IHierarchicalCollectionView = adg.dataProvider as IHierarchicalCollectionView;
+				var adgHD:IHierarchicalData = adgCollection.source; 
+				if (adgHD.hasChildren(item))
+				{
+					var children:ICollectionView = adgCollection.getChildren (item);
+					var cursor:IViewCursor = children.createCursor();
+					while (!cursor.afterLast)
+					{
+						toggleChildren(cursor.current, adg, state);
+						cursor.moveNext();
+					}
+				}
+			}
+		}
+		
+		private function getState(adg:AdvancedDataGrid, parent:Object):String
+		{
+			var noChecks:int = 0;
+			var noCats:int = 0;
+			var noUnChecks:int = 0;
+			if (parent != null)
+			{
+				var adgCollection:IHierarchicalCollectionView = adg.dataProvider as IHierarchicalCollectionView;
+				var cursor:IViewCursor = adgCollection.getChildren(parent).createCursor();
+				while (!cursor.afterLast)
+				{
+					if (cursor.current.@state == STATE_CHECKED)
+					{
+						noChecks++;
+					}
+					else if (cursor.current.@state == STATE_UNCHECKED)
+					{
+						noUnChecks++
+					}
+					else
+					{
+						noCats++;
+					}
+					cursor.moveNext();
+				}
+			}
+			if ((noChecks > 0 && noUnChecks > 0) || (noCats > 0))
+			{
+				return STATE_SCHRODINGER;
+			}
+			else if (noChecks > 0)
+			{
+				return STATE_CHECKED;
+			}
+			else
+			{
+				return STATE_UNCHECKED;
+			}
+		}
+		private function imageToggleHandler(event:MouseEvent):void
+		{
+			myCheckBox.selected = !myCheckBox.selected;
+			checkBoxToggleHandler(event);
+		}
+		private function checkBoxToggleHandler(event:MouseEvent):void
+		{
+			if (data)
+			{
+				var myListData:AdvancedDataGridListData = AdvancedDataGridListData(this.listData);
+				var selectedNode:Object = myListData.item;
+				var adg:AdvancedDataGrid = AdvancedDataGrid(myListData.owner);
+				var toggle:Boolean = myCheckBox.selected;
+				if (toggle)
+				{
+					toggleChildren(data, adg, STATE_CHECKED);
+				}
+				else
+				{
+					toggleChildren(data, adg, STATE_UNCHECKED);
+				}
+				var parent:Object = adg.getParentItem (data);
+				toggleParents (parent, adg, getState (adg, parent));
+			}
+		}
+		
+		override protected function createChildren():void
+		{
+			super.createChildren();
+			myCheckBox = new CheckBox();
+			myCheckBox.setStyle( "verticalAlign", "middle" );
+			myCheckBox.addEventListener( MouseEvent.CLICK, checkBoxToggleHandler );
+			addChild(myCheckBox);
+			myImage = new Image();
+	    	myImage.source = inner;
+			myImage.addEventListener( MouseEvent.CLICK, imageToggleHandler );
+			myImage.setStyle( "verticalAlign", "middle" );
+			addChild(myImage);
+			
+	    }	
+
+		private function setCheckState (checkBox:CheckBox, value:Object, state:String):void
+		{
+			if (state == STATE_CHECKED)
+			{
+				checkBox.selected = true;
+			}
+			else if (state == STATE_UNCHECKED)
+			{
+				checkBox.selected = false;
+			}
+			else if (state == STATE_SCHRODINGER)
+			{
+				checkBox.selected = false;
+			}
+		}	    
+		override public function set data(value:Object):void
+		{
+			super.data = value;
+			
+			setCheckState (myCheckBox, value, value.@state);
+			if(AdvancedDataGridListData(super.listData).item.@type == 'dimension')
+			{
+			    setStyle("fontStyle", 'italic');
+			}
+			else
+			{
+				if (this.parent != null)
+				{
+					var _adg:AdvancedDataGrid = AdvancedDataGrid(this.owner);
+		    		_adg.setStyle("defaultLeafIcon", null);
+		  		}
+				setStyle("fontStyle", 'normal');
+			}
+	    }
+	    
+	   override protected function commitProperties():void
+	   {
+	   	   super.commitProperties();
+           var dg:AdvancedDataGrid = AdvancedDataGrid(listData.owner);
+
+           var column:AdvancedDataGridColumn =
+               dg.columns[listData.columnIndex];
+
+           label.wordWrap = dg.columnWordWrap(column);
+	   }
+	   
+	    /**
+	     *  @private
+	     */
+	    override protected function measure():void
+	    {
+	        super.measure();
+	
+	        var w:Number = data ? AdvancedDataGridListData(listData).indent : 0;
+	
+	        if (disclosureIcon)
+	            w += disclosureIcon.width;
+	
+	        if (icon)
+	            w += icon.measuredWidth;
+
+	        if (myCheckBox)
+	            w += myCheckBox.measuredWidth;
+	
+	        // guarantee that label width isn't zero because it messes up ability to measure
+	        if (label.width < 4 || label.height < 4)
+	        {
+	            label.width = 4;
+	            label.height = 16;
+	        }
+	
+	        if (isNaN(explicitWidth))
+	        {
+	            w += label.getExplicitOrMeasuredWidth();    
+	            measuredWidth = w;
+	        }
+	        else
+	        {
+	            label.width = Math.max(explicitWidth - w, 4);
+	        }
+	        
+	        measuredHeight = label.getExplicitOrMeasuredHeight();
+	        if (icon && icon.measuredHeight > measuredHeight)
+	            measuredHeight = icon.measuredHeight;
+	        if (myCheckBox && myCheckBox.measuredHeight > measuredHeight)
+	            measuredHeight = myCheckBox.measuredHeight;
+	    }
+	   
+
+	   override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+	   {
+			super.updateDisplayList(unscaledWidth, unscaledHeight);
+	        if(super.data)
+	        {
+			    if (super.icon != null)
+			    {
+				    myCheckBox.x = super.icon.x;
+				    myCheckBox.y = (unscaledHeight - myCheckBox.height) / 2;
+				    super.icon.x = myCheckBox.x + myCheckBox.width + 17;
+				    if (icon.x + icon.width > unscaledWidth)
+				    	icon.setActualSize(0, unscaledHeight);
+				    super.label.x = super.icon.x + super.icon.width + 3;
+				    super.label.setActualSize(Math.max(unscaledWidth - super.label.x, 4), unscaledHeight);
+				}
+				else
+			    {
+				    myCheckBox.x = super.label.x;
+				    myCheckBox.y = (unscaledHeight - myCheckBox.height) / 2;
+				    super.label.x = myCheckBox.x + myCheckBox.width + 17;
+				    super.label.setActualSize(Math.max(unscaledWidth - super.label.x, 4), unscaledHeight);
+				}
+				if (myCheckBox.x + myCheckBox.width > unscaledWidth)
+					myCheckBox.visible = false;
+			    if (data.@state == STATE_SCHRODINGER)
+			    {
+			    	myImage.x = myCheckBox.x + 4;
+			    	myImage.y = myCheckBox.y - 3;
+					myImage.width = imageWidth;
+					myImage.height = imageHeight;
+			    }
+			    else
+			    {
+			    	myImage.x = 0;
+			    	myImage.y = 0;
+					myImage.width = 0;
+					myImage.height = 0;
+			    }
+			}
+	    }
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/MultiImageNavigator.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/MultiImageNavigator.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/MultiImageNavigator.mxml	(revision 15)
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
+				   xmlns:s="library://ns.adobe.com/flex/spark" 
+				   xmlns:mx="library://ns.adobe.com/flex/mx"
+				   creationComplete="init()">
+	<fx:Declarations>
+		<!-- Place non-visual elements (e.g., services, value objects) here -->
+	</fx:Declarations>
+	<fx:Script>
+		<![CDATA[
+			import com.degrafa.core.utils.ColorKeys;
+			
+			import mx.controls.Image;
+			import mx.core.Container;
+			import mx.events.ScrollEvent;
+			import mx.graphics.SolidColor;
+			
+			import spark.components.Group;
+			import spark.primitives.Rect;
+			
+			private var _container : MultiImageContainer;
+			private var visibleRectangleGroup : Group;
+			private var rectangle : Rect;
+			
+			public function set container(container : MultiImageContainer) : void
+			{
+				_container = container;
+				updateDisplay();
+				addEventListeners();
+			}
+			
+			public function get container() : MultiImageContainer
+			{
+				return _container;
+			}
+			
+			private function init() : void
+			{
+				visibleRectangleGroup = new Group(); 
+				rectangle = new Rect();
+				rectangle.x = 0;
+				rectangle.y = 0;
+				rectangle.width = 50;
+				rectangle.height = 50;
+				rectangle.radiusX = 0;
+				var rectangleFill : SolidColor = new SolidColor(ColorKeys.BLACK);
+				rectangleFill.alpha = 0.3;
+				rectangle.fill = rectangleFill;
+				visibleRectangleGroup.addElement(rectangle);
+				this.addElement(visibleRectangleGroup);
+				visibleRectangleGroup.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveOnVisibleRectangleGroupEventHandler);
+				visibleRectangleGroup.addEventListener(MouseEvent.MOUSE_OUT, mouseOutOnVisibleRectangleGroupEventHandler);
+			}
+			
+			/**
+			 * Stops minimap drag when mouse left the visible box area
+			 */
+			private function mouseOutOnVisibleRectangleGroupEventHandler(event : MouseEvent) : void
+			{
+				visibleRectangleGroup.stopDrag();
+			}
+			
+			/**
+			 * Move visible rectangle with mouse drag behaviour
+			 */
+			private function mouseMoveOnVisibleRectangleGroupEventHandler(event : MouseEvent) : void
+			{
+				if (event.buttonDown)
+				{
+					visibleRectangleGroup.startDrag(false, new Rectangle(0,0,this.width - rectangle.width, this.height - rectangle.height));
+					updateContainerPosition();
+				}
+				else visibleRectangleGroup.stopDrag();
+			}
+			
+			private function updateContainerPosition() : void
+			{
+				_container.scroll(((visibleRectangleGroup.x) / (this.width - visibleRectangleGroup.width)) * (_container.width - _container.parent.width)
+					,((visibleRectangleGroup.y) / (this.height - visibleRectangleGroup.height)) * (_container.height - _container.parent.height));
+			}
+			
+			private function updateDisplay() : void
+			{
+				var ratio : Number = _container.width / _container.height;
+				if (ratio < 1)
+					this.width = this.height * ratio;
+				else
+					this.height = this.width / ratio;
+				var xScale : Number = _container.width / this.width;
+				var yScale : Number = _container.height / this.height;
+				for each (var img : Image in _container.gallery)
+				{
+					var temp : Image = new Image();
+					temp.source = img.source;
+					temp.width = img.width / xScale;
+					temp.height = img.height / yScale;
+					temp.x = img.x / xScale;
+					temp.y = img.y / yScale;
+					this.addElement(temp);
+				}
+				rectangle.width = this.width *  _container.parent.width / _container.width;
+				rectangle.height = this.height * _container.parent.height / _container.height;
+				this.setElementIndex(visibleRectangleGroup, _container.gallery.length);
+			}
+			
+			private function addEventListeners() : void
+			{
+				var tmp : Container = _container.parent as Container;
+				tmp.addEventListener(ScrollEvent.SCROLL, containerScrolled);
+			}
+			
+			private function containerScrolled(event : ScrollEvent) : void
+			{
+				var tmp : Container = _container.parent as Container;
+				visibleRectangleGroup.x = tmp.horizontalScrollPosition * (this.width - visibleRectangleGroup.width) / (_container.width - _container.parent.width);
+				visibleRectangleGroup.y = tmp.verticalScrollPosition * (this.height - visibleRectangleGroup.height) / (_container.height - _container.parent.height);
+			}
+			
+		]]>
+	</fx:Script>
+</s:BorderContainer>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CheckTreeRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CheckTreeRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/CheckTreeRenderer.as	(revision 15)
@@ -0,0 +1,226 @@
+package gssim.gssimstudio.editor.gssim.components
+{
+	import mx.controls.Image;
+	import mx.controls.Tree;
+	import mx.controls.treeClasses.*;
+	import mx.collections.*;
+	import mx.controls.CheckBox;
+	import mx.controls.listClasses.*;
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+	import mx.events.FlexEvent;
+	import flash.display.DisplayObject;
+	import flash.events.MouseEvent;
+	import flash.xml.*;
+	
+	import mx.core.IDataRenderer;
+	
+
+	public class CheckTreeRenderer extends TreeItemRenderer
+	{
+        protected var myImage:Image;
+        
+        // set image properties
+        private var imageWidth:Number 	= 6;
+	    private var imageHeight:Number 	= 6;
+        private var inner:String 	= "assets/inner.png";
+		protected var myCheckBox:CheckBox;
+		static private var STATE_SCHRODINGER:String = "schrodinger";
+		static private var STATE_CHECKED:String = "checked";
+		static private var STATE_UNCHECKED:String = "unchecked";
+	    
+        public function CheckTreeRenderer () 
+		{
+			super();
+			mouseEnabled = false;
+		}
+		private function toggleParents (item:Object, tree:Tree, state:String):void
+		{
+			if (item == null)
+			{
+				return;
+			}
+			else
+			{
+				item.@state = state;
+				toggleParents(tree.getParentItem(item), tree, getState (tree, tree.getParentItem(item)));
+			}
+		}
+		
+		private function toggleChildren (item:Object, tree:Tree, state:String):void
+		{
+			if (item == null)
+			{
+				return;
+			}
+			else
+			{
+				item.@state = state;
+				var treeData:ITreeDataDescriptor = tree.dataDescriptor;
+				if (treeData.hasChildren(item))
+				{
+					var children:ICollectionView = treeData.getChildren (item);
+					var cursor:IViewCursor = children.createCursor();
+					while (!cursor.afterLast)
+					{
+						toggleChildren(cursor.current, tree, state);
+						cursor.moveNext();
+					}
+				}
+			}
+		}
+		
+		private function getState(tree:Tree, parent:Object):String
+		{
+			var noChecks:int = 0;
+			var noCats:int = 0;
+			var noUnChecks:int = 0;
+			if (parent != null)
+			{
+				var treeData:ITreeDataDescriptor = tree.dataDescriptor;
+				var cursor:IViewCursor = treeData.getChildren(parent).createCursor();
+				while (!cursor.afterLast)
+				{
+					if (cursor.current.@state == STATE_CHECKED)
+					{
+						noChecks++;
+					}
+					else if (cursor.current.@state == STATE_UNCHECKED)
+					{
+						noUnChecks++
+					}
+					else
+					{
+						noCats++;
+					}
+					cursor.moveNext();
+				}
+			}
+			if ((noChecks > 0 && noUnChecks > 0) || (noCats > 0))
+			{
+				return STATE_SCHRODINGER;
+			}
+			else if (noChecks > 0)
+			{
+				return STATE_CHECKED;
+			}
+			else
+			{
+				return STATE_UNCHECKED;
+			}
+		}
+		private function imageToggleHandler(event:MouseEvent):void
+		{
+			myCheckBox.selected = !myCheckBox.selected;
+			checkBoxToggleHandler(event);
+		}
+		private function checkBoxToggleHandler(event:MouseEvent):void
+		{
+			if (data)
+			{
+				var myListData:TreeListData = TreeListData(this.listData);
+				var selectedNode:Object = myListData.item;
+				var tree:Tree = Tree(myListData.owner);
+				var toggle:Boolean = myCheckBox.selected;
+				if (toggle)
+				{
+					toggleChildren(data, tree, STATE_CHECKED);
+				}
+				else
+				{
+					toggleChildren(data, tree, STATE_UNCHECKED);
+				}
+				var parent:Object = tree.getParentItem (data);
+				toggleParents (parent, tree, getState (tree, parent));
+			}
+		}
+		
+		override protected function createChildren():void
+		{
+			super.createChildren();
+			myCheckBox = new CheckBox();
+			myCheckBox.setStyle( "verticalAlign", "middle" );
+			myCheckBox.setStyle( "paddingTop", "15" );
+			myCheckBox.addEventListener( MouseEvent.CLICK, checkBoxToggleHandler );
+			addChild(myCheckBox);
+			myImage = new Image();
+	    	myImage.source = inner;
+			myImage.addEventListener( MouseEvent.CLICK, imageToggleHandler );
+			myImage.setStyle( "verticalAlign", "middle" );
+			addChild(myImage);
+			
+	    }	
+
+		private function setCheckState (checkBox:CheckBox, value:Object, state:String):void
+		{
+			if (state == STATE_CHECKED)
+			{
+				checkBox.selected = true;
+			}
+			else if (state == STATE_UNCHECKED)
+			{
+				checkBox.selected = false;
+			}
+			else if (state == STATE_SCHRODINGER)
+			{
+				checkBox.selected = false;
+			}
+		}	    
+		override public function set data(value:Object):void
+		{
+			super.data = value;
+			
+			if (myCheckBox == null) return;
+			
+			setCheckState (myCheckBox, value, value.@state);
+			if(TreeListData(super.listData).item.@type == 'dimension')
+			{
+			    setStyle("fontStyle", 'italic');
+			}
+			else
+			{
+				if (this.parent != null)
+				{
+					var _tree:Tree = Tree(this.parent.parent);
+		    		_tree.setStyle("defaultLeafIcon", null);
+		  		}
+				setStyle("fontStyle", 'normal');
+			}
+	    }
+
+	   override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+	   {
+			super.updateDisplayList(unscaledWidth, unscaledHeight);
+	        if(super.data)
+	        {
+			    if (super.icon != null)
+			    {
+				    myCheckBox.x = super.icon.x;
+				    myCheckBox.y = 2;
+				    super.icon.x = myCheckBox.x + myCheckBox.width + 17;
+				    super.label.x = super.icon.x + super.icon.width + 3;
+				}
+				else
+			    {
+				    myCheckBox.x = super.label.x;
+				    myCheckBox.y = 2;
+				    super.label.x = myCheckBox.x + myCheckBox.width + 17;
+				}
+			    if (data.@state == STATE_SCHRODINGER)
+			    {
+			    	myImage.x = myCheckBox.x + 4;
+			    	myImage.y = myCheckBox.y + 4;
+					myImage.width = imageWidth;
+					myImage.height = imageHeight;
+			    }
+			    else
+			    {
+			    	myImage.x = 0;
+			    	myImage.y = 0;
+					myImage.width = 0;
+					myImage.height = 0;
+			    }
+			}
+	    }
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/IconButton.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/IconButton.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/IconButton.as	(revision 15)
@@ -0,0 +1,25 @@
+package gssim.gssimstudio.editor.gssim.components
+{
+	import spark.components.Button;
+	
+	//icons
+	[Style(name="iconUp",type="*")]
+	[Style(name="iconOver",type="*")]
+	[Style(name="iconDown",type="*")]
+	[Style(name="iconDisabled",type="*")]
+	//paddings
+	[Style(name="paddingLeft",type="Number")]
+	[Style(name="paddingRight",type="Number")]
+	[Style(name="paddingTop",type="Number")]
+	[Style(name="paddingBottom",type="Number")]
+	/**
+	 * Button with additional style properties
+	 */
+	public class IconButton extends Button
+	{
+		public function IconButton()
+		{
+			super();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/IconToggleButton.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/IconToggleButton.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/IconToggleButton.as	(revision 15)
@@ -0,0 +1,31 @@
+package gssim.gssimstudio.editor.gssim.components
+{
+	import spark.components.ToggleButton;
+	
+	//icons
+	[Style(name="iconUp",type="*")]
+	[Style(name="iconOver",type="*")]
+	[Style(name="iconDown",type="*")]
+	[Style(name="iconDisabled",type="*")]
+	[Style(name="iconSelectedUp",type="*")]
+	[Style(name="iconSelectedOver",type="*")]
+	[Style(name="iconSelectedDown",type="*")]
+	[Style(name="iconSelectedDisabled",type="*")]
+	//paddings
+	[Style(name="paddingLeft",type="Number")]
+	[Style(name="paddingRight",type="Number")]
+	[Style(name="paddingTop",type="Number")]
+	[Style(name="paddingBottom",type="Number")]
+	/**
+	 * Toggle button with additional style properties
+	 */
+	public class IconToggleButton extends ToggleButton
+	{
+		public var menu : RollOutMenu;
+		
+		public function IconToggleButton()
+		{
+			super();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/TextInputWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/TextInputWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/TextInputWindow.mxml	(revision 15)
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" 
+				title="Input text title window">
+	
+	<mx:Script>
+		<![CDATA[       
+			import gssim.gssimstudio.editor.script.event.TextMessageEvent;
+			
+			import mx.controls.Text;
+			import mx.events.CloseEvent;
+			import mx.managers.PopUpManager;
+			
+			public function init(title : String, promptText : String) : void
+			{
+				this.title = title;
+				prompt.text = promptText + ": ";
+			}
+			
+			private function returnString():void {
+				dispatchEvent(new TextMessageEvent(CloseEvent.CLOSE, input.text));
+				PopUpManager.removePopUp(this);
+			}
+		]]>
+	</mx:Script>
+	
+	<mx:HBox>
+		<mx:Label id="prompt" text="Enter text: "/>
+		<mx:TextInput id="input" width="100%"/>
+	</mx:HBox>
+	
+	<mx:HBox>
+		<mx:Button label="OK" click="returnString();" enabled="{input.text != ''}"/>
+		<mx:Button label="Cancel" click="PopUpManager.removePopUp(this);"/>
+	</mx:HBox>
+	
+</mx:TitleWindow>  
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/TimePicker.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/TimePicker.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/components/TimePicker.mxml	(revision 15)
@@ -0,0 +1,383 @@
+<!--
+Copyright (c) 2007 Stretch Media Group
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Features:
+
+- Provides time entry for hours, minutes and seconds in 24 and 12 hour format  
+- Resizable to fit various text sizes, and also allows for styling of stepper buttons, border, and background
+- Can use numeric stepper to increase/decrease hour, minute, second, am/pm entries
+- Can use keyboard up/down, left/right to increase/decrease hour, minute, second, am/pm entries
+- Hour, minute, second, am/pm entries wrap if reaching max/min values
+- Can tab through fields
+- Can enable/disable component
+- Easily provide hour/minute/text values for preset/updatable time
+
+Properties: 
+
+hour : the numeric value of the selected hour (if provided, overrides the defaultHour value)
+minute : the numeric value of the selected minute (if provided, overrides the defaultMinute value)
+second : the numeric value of the selected second (if provided, overrides the defaultSecond value)
+am_pm : the string value of the selected am/pm entry ("am", "pm")
+defaultHour : the hour which you want the selector to default to (is overriden if hour argument is provided)
+defaultMinute : the minute which you want the selector to default to (is overriden if minute argument is provided)
+defaultSecond : the second which you want the selector to default to (is overriden if second argument is provided)
+showSeconds : show seconds entry in selector
+is24Hour : if false hour selector allows range of 1-12 and am/pm entry is enabled
+           if true hour selector allows range of 0-23 and am/pm entry is disabled
+
+-->
+
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"  
+           creationComplete="createComplete();">
+
+    <mx:NumberValidator id="hourValidator" source="{hourText}" exceedsMaxError="" lowerThanMinError="" integerError=""
+                        property="text" maxValue="{maxHour}" minValue="{minHour}"
+                        trigger="{hourText}" triggerEvent="change" invalid="hourText.text = String(maxHour); hourText.errorString = '';" />
+    <mx:NumberValidator id="minuteValidator" source="{minuteText}" exceedsMaxError="" lowerThanMinError="" integerError=""
+                        property="text" maxValue="59" minValue="0" 
+                        trigger="{minuteText}" triggerEvent="change" invalid="minuteText.text = '59'" allowNegative="false"  />
+    <mx:NumberValidator id="secondValidator" source="{secondText}" exceedsMaxError="" lowerThanMinError="" integerError=""
+                        property="text" maxValue="59" minValue="0" 
+                        trigger="{secondText}" triggerEvent="change" invalid="secondText.text = '59'" allowNegative="false"  />
+    
+    <mx:NumericStepper id="timeStepper" x="0" y="0" height="100%" width="100" fontSize="0" textAlign="right" paddingLeft="100"
+                       focusAlpha="0" borderThickness="0" borderStyle="none" maximum="99" minimum="-99"
+                       change="changeStepValue(event)" backgroundAlpha="0" color="{this.getStyle('backgroundColor')}"
+                       click="_focusArea.setFocus();" focusEnabled="false"/>
+       
+       <mx:HBox id="timeBox" x="3" y="2" horizontalGap="0" verticalAlign="middle" height="100%"
+           horizontalScrollPolicy="off"
+            verticalScrollPolicy="off" backgroundAlpha="0" creationComplete="setTimeStepperPosition();">
+            
+            
+        <mx:TextInput id="hourText" height="100%" borderThickness="0" borderStyle="none" backgroundAlpha="0" 
+                      textAlign="center" maxChars="2"
+                      text="{formatText(String(hour), 'hourText')}" 
+                      keyDown="keyHandler(event)" mouseUp="setTextFocus(event)" mouseDown="setTextFocus(event)" 
+                      focusOut="fixText(event)" focusIn="setTextFocus(event)" change="setValues(event)"
+                      focusAlpha="0" errorString=""/>
+                          
+                        <mx:Spacer width="-8" /><mx:Label text=":" /><mx:Spacer width="-16" />
+            
+        <mx:TextInput id="minuteText" height="100%" borderThickness="0" borderStyle="none" backgroundAlpha="0" 
+                      textAlign="center" maxChars="2"
+                      text="{formatText(String(minute), 'minuteText')}" 
+                      keyDown="keyHandler(event)" mouseUp="setTextFocus(event)" mouseDown="setTextFocus(event)"
+                      focusOut="fixText(event)" focusIn="setTextFocus(event)" change="setValues(event)"
+                      focusAlpha="0"   />
+            
+                        <mx:Spacer width="-8" includeInLayout="{showSeconds}" visible="{showSeconds}" />
+                        <mx:Label text=":" includeInLayout="{showSeconds}" visible="{showSeconds}" />
+                        <mx:Spacer width="-16" includeInLayout="{showSeconds}" visible="{showSeconds}" />
+            
+        <mx:TextInput id="secondText" height="100%" borderThickness="0" borderStyle="none" backgroundAlpha="0" 
+                      textAlign="center" maxChars="2"
+                      text="{formatText(String(second), 'secondText')}"
+                      keyDown="keyHandler(event)" mouseUp="setTextFocus(event)" mouseDown="setTextFocus(event)" 
+                      focusOut="fixText(event)" focusIn="setTextFocus(event)" change="setValues(event)"
+                      focusAlpha="0" 
+                      includeInLayout="{showSeconds}" visible="{showSeconds}" />
+        
+                        <mx:Spacer width="-8" includeInLayout="{!is24Hour}" visible="{!is24Hour}" />
+            
+        
+        <mx:TextInput id="amPMText" height="100%" borderThickness="0" borderStyle="none" backgroundAlpha="0" 
+                      textAlign="center" maxChars="2"
+                      text="{this.am_pm}" 
+                      keyDown="amPMKeyHandler(event)" mouseUp="setTextFocus(event)" mouseDown="setTextFocus(event)" 
+                      focusAlpha="0" focusIn="setTextFocus(event)" 
+                      editable="false" includeInLayout="{!is24Hour}" visible="{!is24Hour}"  />
+                      
+                        <mx:Spacer width="-5" includeInLayout="{!is24Hour}" visible="{!is24Hour}" />
+                        
+    </mx:HBox> 
+    
+       
+       <mx:Script>
+           <![CDATA[
+            import mx.controls.NumericStepper;
+            import mx.events.NumericStepperEvent;
+            import mx.core.UITextField;
+            import flash.events.MouseEvent;
+            
+            
+            private var _timeValue:Object;
+            private var _focusArea:TextInput;
+            private var _focusText:TextField;
+            private var _currentStepValue:Number;
+            [Bindable] private var maxHour:Number;
+            [Bindable] private var minHour:Number;
+           
+           
+            [Bindable] public var hour:Number = 0;
+            [Bindable] public var minute:Number = 0;
+            [Bindable] public var second:Number = 0;
+            [Bindable] public var am_pm:String = 'am';
+            [Bindable] public var showSeconds:Boolean;
+            [Bindable] public var is24Hour:Boolean;
+            public var defaultHour:Number;
+            public var defaultMinute:Number = 0;
+            public var defaultSecond:Number = 0;
+            
+            
+            
+            public function get timeValue():Object
+            {
+                var tmpTime:Object = new Object();
+                tmpTime.hour = this.hour;
+                tmpTime.minute = this.minute;
+                tmpTime.second = this.second;
+                return tmpTime;
+            }
+            
+            public function set timeValue(value:Object):void
+            {
+                this._timeValue = value;
+            }
+            
+            private function createComplete():void
+            {
+                
+                if(!this.hour) 
+                {
+                    String(this.hour);
+                    this.hour = Number(hourText.text);
+                }
+                else
+                {
+                    if(defaultHour)
+                    {
+                        hourText.text = String(defaultHour);
+                    }
+                    else
+                    {
+                        (is24Hour) ? hourText.text = "12" : hourText.text = "1";
+                    }  
+                }
+                if(!this.minute)
+                {
+                    minuteText.text = (defaultMinute < 10) ? "0" + String(defaultMinute) : String(defaultMinute);
+                    this.minute = Number(minuteText.text);
+                }
+                if(!this.second)
+                {
+                    secondText.text = (defaultSecond < 10) ? "0" + String(defaultSecond) : String(defaultSecond);
+                    this.second = Number(secondText.text);
+                }
+                
+                if(!this.am_pm)
+                {
+                    this.am_pm = (is24Hour) ? 'pm' : "am";;
+                }
+                
+                (is24Hour) ? maxHour = 23 : maxHour = 12;
+                (is24Hour) ? minHour = 0 : minHour = 1;
+                
+                if(!_focusArea) 
+                {
+                    _focusArea = hourText;
+                    _currentStepValue = Number(_focusArea.text);
+                    timeStepper.value = _currentStepValue;
+                }    
+                
+            }
+            private function setTextFocus(event:Event):void
+            {
+                _focusArea = event.currentTarget as TextInput;
+                _focusText = event.target as TextField;
+                TextField(event.target).setSelection(0, 2);
+                if(event.currentTarget != amPMText)
+                {
+                    _currentStepValue = Number(_focusArea.text);
+                    timeStepper.value = _currentStepValue;
+                }
+                setStepValue();
+                
+            }
+            
+            private function setTimeStepperPosition():void
+            {
+                if(timeBox) timeStepper.x = (!is24Hour) ? (timeBox.width - (timeStepper.width * 0.72)) : timeBox.width - (timeStepper.width * 0.8);
+            }
+            
+            private function setStepValue():void
+            {
+                if(_focusArea == amPMText)
+                {
+                    timeStepper.minimum = -99;
+                    timeStepper.maximum = 99;
+                }
+            }
+            
+            private function changeStepValue(event:Event):void
+            {
+                if(_focusArea != amPMText)
+                {
+                    if(_focusArea == hourText)
+                    {
+                        var tmpMinValue:Number = (is24Hour) ? 0 : 1;
+                        if(NumericStepper(event.target).value > maxHour)
+                        {
+                            NumericStepper(event.target).value = (is24Hour) ? 0 : 1;
+                        }
+                        else if(NumericStepper(event.target).value < tmpMinValue)
+                        {
+                            NumericStepper(event.target).value = (is24Hour) ? 23 : 12;
+                        }
+                    }
+                    if(_focusArea == minuteText || _focusArea == secondText)
+                    {
+                        if(NumericStepper(event.target).value > 59)
+                        {
+                            NumericStepper(event.target).value = 0;
+                        }
+                        else if(NumericStepper(event.target).value < 0)
+                        {
+                            NumericStepper(event.target).value = 59;
+                        }
+                    }
+                    
+                    _focusArea.setFocus();
+                    if(_focusArea == hourText) this.hour = NumericStepper(event.target).value;
+                    if(_focusArea == minuteText) this.minute = NumericStepper(event.target).value;
+                    if(_focusArea == secondText) this.second = NumericStepper(event.target).value;
+                }
+                else
+                {
+                    amPMText.text = (amPMText.text == "am") ? "pm" : "am";
+                    this.am_pm = amPMText.text;
+                }
+            }
+            
+            private function fixText(event:Event):void
+            {
+                if(!(event.currentTarget == hourText && !is24Hour))
+                {
+                    _focusArea.text = (_focusArea.text.length < 2) ? "0" + _focusArea.text : _focusArea.text;
+                }
+                _focusArea.setSelection(0, 2);
+                if(event.currentTarget == hourText) this.hour = Number(event.currentTarget.text);
+                if(event.currentTarget == minuteText) this.minute = Number(timeStepper.value);
+                if(event.currentTarget == secondText) this.second = Number(timeStepper.value);
+            }
+            
+            private function setValues(event:Event):void
+            {
+                if(event.currentTarget == hourText)
+                {
+                    if(hourValidator.validate(Number(event.currentTarget.text))) timeStepper.value = Number(event.currentTarget.text);
+                }
+                if(event.currentTarget == minuteText)
+                {
+                    if(minuteValidator.validate(Number(event.currentTarget.text))) timeStepper.value = Number(event.currentTarget.text);
+                }
+                if(event.currentTarget == secondText)
+                {
+                    if(secondValidator.validate(Number(event.currentTarget.text))) timeStepper.value = Number(event.currentTarget.text);
+                }
+            }
+            
+            private function formatText(value:String, theField:String):String
+            {
+                if(_focusArea) _focusArea.setSelection(0, 2);
+                if(Number(value) > 12 && !is24Hour && theField == 'hourText')
+                {
+                    value = String(Number(value) % 12);
+                }
+                if(theField == 'hourText' && !is24Hour)
+                {
+                    return value;
+                }
+                else
+                {
+                    return (value.length < 2) ? ("0" + value) : value;
+                }
+            }
+            
+            private function keyHandler(event:KeyboardEvent):void
+            {
+                if(event.keyCode == 39 || event.keyCode == 38) 
+                {
+                    if(_focusArea == hourText)
+                    {
+                        _currentStepValue++;
+                        var tmpMaxValue:Number = (is24Hour) ? (maxHour) : maxHour;
+                        if(_currentStepValue > tmpMaxValue)
+                        {
+                            _currentStepValue = (is24Hour) ? 0 : 1;
+                        }
+
+                      }
+                    else if(_focusArea == minuteText || _focusArea == secondText )
+                    {
+                        _currentStepValue++;
+                        if(_currentStepValue > 59)
+                        {
+                            _currentStepValue = 0;
+                        }
+                        
+                    }
+                    timeStepper.value = _currentStepValue;
+                    timeStepper.dispatchEvent(new NumericStepperEvent('change'));
+                    _focusArea.setSelection(0, 2);
+                }
+                if(event.keyCode == 37 || event.keyCode == 40) 
+                {
+                    if(_focusArea == hourText)
+                    {
+                        _currentStepValue--;
+                        var tmpMinValue:Number = (is24Hour) ? 0 : 1;
+                        if(_currentStepValue < tmpMinValue)
+                        {
+                            _currentStepValue = (is24Hour) ? 23 : 12;
+                        }
+                    }
+                    else if(_focusArea == minuteText || _focusArea == secondText )
+                    {
+                        _currentStepValue--;
+                        if(_currentStepValue < 0)
+                        {
+                            _currentStepValue = 59;
+                        }
+                    }
+                    timeStepper.value = _currentStepValue;
+                    timeStepper.dispatchEvent(new NumericStepperEvent('change'));
+                    _focusArea.setSelection(0, 2);
+                }
+            }
+            
+            private function amPMKeyHandler(event:KeyboardEvent):void
+            {
+                if(event.keyCode == 38 || event.keyCode == 40 || event.keyCode == 37 || event.keyCode == 39) 
+                {
+                    amPMText.text = (amPMText.text == "am") ? "pm" : "am";
+                    this.am_pm = amPMText.text;
+                    _focusArea.setSelection(0, 2);
+                }
+                
+            }
+           ]]>
+       </mx:Script>
+       
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/skins/IconButtonSkin.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/skins/IconButtonSkin.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/skins/IconButtonSkin.mxml	(revision 15)
@@ -0,0 +1,86 @@
+<s:SparkSkin
+	xmlns:fx="http://ns.adobe.com/mxml/2009"
+	xmlns:s="library://ns.adobe.com/flex/spark"
+	xmlns:mx="library://ns.adobe.com/flex/mx"
+	currentStateChanging="onCurrentStateChanging(event)"
+	>
+	<fx:Metadata>
+		[HostComponent("gssim.gssimstudio.editor.gssim.components.IconButton")]
+	</fx:Metadata>
+	<fx:Script>
+		<![CDATA[
+			import mx.events.StateChangeEvent;
+			
+			private function onCurrentStateChanging(event:StateChangeEvent):void{
+				switch(event.newState){
+					case "up":
+						setIcon("iconUp");
+						break;
+					case "over":
+						setIcon("iconOver");
+						break;
+					case "down":
+						setIcon("iconDown");
+						break;
+					case "disabled":
+						setIcon("iconDisabled");
+						break;
+				}
+			}
+			private function setIcon(type:String):void{
+				if(hostComponent.getStyle(type) != null){
+					icon.source = hostComponent.getStyle(type);
+				}
+			}
+			
+		]]>
+	</fx:Script>
+	<s:layout>
+		<s:BasicLayout/>
+	</s:layout>
+	<s:states>
+		<s:State name="up"/>
+		<s:State name="over"/>
+		<s:State name="down"/>
+		<s:State name="disabled"/>
+	</s:states> 
+	
+	<s:Rect left="0" right="0" top="0" bottom="0" width="69" height="20" radiusX="2" radiusY="2" >
+		<s:stroke>
+			<s:SolidColorStroke id="outline" weight="1" alpha="0"/>
+		</s:stroke>
+		<s:fill>
+			<mx:LinearGradient>
+				<mx:GradientEntry color="#ffffff" ratio="0" alpha="0"/>
+				<mx:GradientEntry color="#cccccc" ratio="1" alpha="0"/>
+			</mx:LinearGradient>
+		</s:fill>
+	</s:Rect>
+	<s:Group
+		horizontalCenter="0"
+		verticalCenter="0"
+		>
+		<s:layout>
+			<s:HorizontalLayout
+				paddingBottom="{ hostComponent.getStyle('paddingBottom')}"
+				paddingTop="{ hostComponent.getStyle('paddingTop')}"
+				paddingLeft="{ hostComponent.getStyle('paddingLeft')}"
+				paddingRight="{ hostComponent.getStyle('paddingRight')}" />
+		</s:layout>
+		<mx:Image
+			id="icon"
+			source="{hostComponent.getStyle('iconUp')}"
+			verticalCenter="0"
+			alpha="0.8"
+			alpha.up="1"
+			/>
+		<s:Label
+			text="{hostComponent.label}"
+			verticalCenter="0"
+			height="100%"
+			verticalAlign="middle"
+			includeInLayout="{( hostComponent.label != '' )}"
+			visible="{( hostComponent.label != '' )}"/>
+	</s:Group>
+	
+</s:SparkSkin>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/skins/IconToggleButtonSkin.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/skins/IconToggleButtonSkin.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/skins/IconToggleButtonSkin.mxml	(revision 15)
@@ -0,0 +1,98 @@
+<s:SparkSkin
+	xmlns:fx="http://ns.adobe.com/mxml/2009"
+	xmlns:s="library://ns.adobe.com/flex/spark"
+	xmlns:mx="library://ns.adobe.com/flex/mx"
+	currentStateChanging="onCurrentStateChanging(event)"
+	>
+	<fx:Metadata>
+		[HostComponent("gssim.gssimstudio.editor.gssim.components.IconToggleButton")]
+	</fx:Metadata>
+	<fx:Script>
+		<![CDATA[
+			import mx.events.StateChangeEvent;
+			
+			private function onCurrentStateChanging(event:StateChangeEvent):void{
+				switch(event.newState){
+					case "up":
+						setIcon("iconUp");
+						break;
+					case "upAndSelected":
+						setIcon("iconSelectedUp");
+						break;
+					case "over":
+						setIcon("iconOver");
+						break;
+					case "overAndSelected":
+						setIcon("iconSelectedOver");
+						break;
+					case "down":
+						setIcon("iconDown");
+						break;
+					case "downAndSelected":
+						setIcon("iconSelectedDown");
+						break;
+					case "disabled":
+						setIcon("iconDisabled");
+						break;
+					case "disabledAndSelected":
+						setIcon("iconSelectedDisabled");
+						break;
+				}
+			}
+			private function setIcon(type:String):void{
+				if(hostComponent.getStyle(type) != null){
+					icon.source = hostComponent.getStyle(type);
+				}
+			}
+			
+		]]>
+	</fx:Script>
+	<s:layout>
+		<s:BasicLayout/>
+	</s:layout>
+	<s:states>
+		<s:State name="up"/>
+		<s:State name="over"/>
+		<s:State name="down"/>
+		<s:State name="disabled"/>
+		<s:State name="upAndSelected"/>
+		<s:State name="overAndSelected"/>
+		<s:State name="downAndSelected"/>
+		<s:State name="disabledAndSelected"/>
+	</s:states> 
+	
+	<s:Rect left="0" right="0" top="0" bottom="0" width="69" height="20" radiusX="15" radiusY="15" >
+		<s:stroke>
+			<s:SolidColorStroke id="outline" weight="1"/>
+		</s:stroke>
+		<s:fill>
+			<mx:LinearGradient>
+				<mx:GradientEntry color="#ffffff" ratio="0"/>
+				<mx:GradientEntry color="#cccccc" ratio="1"/>
+			</mx:LinearGradient>
+		</s:fill>
+	</s:Rect>
+	<s:Group
+		horizontalCenter="0"
+		verticalCenter="0"
+		>
+		<s:layout>
+			<s:HorizontalLayout
+				paddingBottom="{ hostComponent.getStyle('paddingBottom')}"
+				paddingTop="{ hostComponent.getStyle('paddingTop')}"
+				paddingLeft="{ hostComponent.getStyle('paddingLeft')}"
+				paddingRight="{ hostComponent.getStyle('paddingRight')}" />
+		</s:layout>
+		<mx:Image
+			id="icon"
+			source="{hostComponent.getStyle('iconUp')}"
+			alpha="0.8"
+			alpha.up="1"
+			/>
+		<s:Label height="100%"
+			text="{hostComponent.label}"
+			includeInLayout="{( hostComponent.label != '' )}"
+			visible="{( hostComponent.label != '' )}" verticalAlign="middle"/>
+	</s:Group>
+	
+</s:SparkSkin>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/flexmdi/MDIWindowNoMaximize.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/flexmdi/MDIWindowNoMaximize.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/flexmdi/MDIWindowNoMaximize.as	(revision 15)
@@ -0,0 +1,37 @@
+package gssim.gssimstudio.editor.gssim.flexmdi
+{
+	import flexlib.mdi.containers.MDIWindow;
+	import flash.ui.ContextMenu;
+    import flash.ui.ContextMenuItem;
+    import flash.events.ContextMenuEvent;
+
+	/**
+	 * MDI window without maximization feature (and not resizeable)
+	 */
+	public class MDIWindowNoMaximize extends MDIWindow
+	{
+		public var originalX : Number = 0;
+		public var originalY : Number = 0;
+		
+		public function MDIWindowNoMaximize()
+		{
+			super();
+			
+			resizable = false;
+			
+			//hack :)
+			//remove button from the top right corner
+			maximizeRestoreBtn.parent.removeChild(maximizeRestoreBtn);
+		}
+		
+		/**
+		 * Disable maximize functionality
+		 */
+		public override function maximize():void
+        {
+        	//additional future (not used yet)
+        	//TweenLite.to(this, 0.25, {x : originalX, y : originalY});
+        }
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/multiDrag/MultiDragContainer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/multiDrag/MultiDragContainer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/multiDrag/MultiDragContainer.as	(revision 15)
@@ -0,0 +1,92 @@
+package gssim.gssimstudio.editor.gssim.multiDrag
+{
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	
+	/**
+	 * Class for handling multiple object selection and drag.
+	 */
+	public class MultiDragContainer
+	{
+		/**
+		 * Map containing objects of group
+		 */
+		private var dragGroup : Object; //map id -> Object
+		/**
+		 * Starting point of the drag operation
+		 */
+		private var startDragPositionX : Number;
+		private var startDragPositionY : Number;
+		/**
+		 * Distance counter during mouse drag
+		 */
+		private var diffX : Number;
+		private var diffY : Number;			 
+			 
+		public function MultiDragContainer()
+		{
+			empty();
+		}
+
+		/**
+		 * Add object to the group
+		 */
+		public function AddObject(object : GenderObject) : void
+		{
+			if (!dragGroup.hasOwnProperty(object.id))
+			{
+				dragGroup[object.id] = object;
+				object.selected = true;
+			}
+		}
+		
+		/**
+		 * Check if object is already in group
+		 */
+		public function Contains(object : GenderObject) : Boolean
+		{
+			return dragGroup.hasOwnProperty(object.id);
+		}
+
+		/**
+		 * Empty the group
+		 */
+		public function empty() : void
+		{
+			for each (var object : GenderObject in dragGroup)
+			{
+				object.selected = false;
+			}
+			dragGroup = new Object();
+			diffX = 0;
+			diffY = 0;
+		}
+		
+		/**
+		 * Set relative start position and reset distance counters (diffX, diffY)
+		 */
+		public function setStartPosition(object : GenderObject) : void
+		{
+			startDragPositionX = object.x;
+			startDragPositionY = object.y;
+			diffX = 0;
+			diffY = 0;
+		}
+		
+		/**
+		 * Move all objects in group
+		 */
+		public function applyDrag(relative : GenderObject) : void
+		{
+			for each (var object : GenderObject in dragGroup)
+			{
+				object.dispatchMoveAction();
+				if (object == relative) continue;
+				object.x += relative.x - startDragPositionX - diffX;
+				object.y += relative.y - startDragPositionY - diffY;
+			}
+			diffX = relative.x - startDragPositionX;
+			diffY = relative.y - startDragPositionY;
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/multiDrag/SelectionBox.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/multiDrag/SelectionBox.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/multiDrag/SelectionBox.as	(revision 15)
@@ -0,0 +1,100 @@
+package gssim.gssimstudio.editor.gssim.multiDrag
+{
+	import com.degrafa.core.utils.ColorKeys;
+	
+	import gssim.gssimstudio.editor.flare.util.Colors;
+	
+	import mx.graphics.SolidColor;
+	import mx.graphics.SolidColorStroke;
+	
+	import spark.components.Group;
+	import spark.primitives.Rect;
+	
+	/**
+	 * Class for handling selection box on the surface
+	 */
+	public class SelectionBox extends Group
+	{
+		private var _selectionRectangle : Rect;
+		
+		public function SelectionBox()
+		{
+			_selectionRectangle = new Rect();
+			_selectionRectangle.x = 0;
+			_selectionRectangle.y = 0;
+			_selectionRectangle.width = 0;
+			_selectionRectangle.height = 0;
+			_selectionRectangle.radiusX = 0;
+			var rectangleFill : SolidColor = new SolidColor(ColorKeys.BLACK);
+			rectangleFill.alpha = 0.0;
+			_selectionRectangle.fill = rectangleFill;
+			var rectangleStroke : SolidColorStroke = new SolidColorStroke(ColorKeys.DARKGREEN);
+			rectangleStroke.weight = 1;
+			_selectionRectangle.stroke = rectangleStroke;
+			this.addElement(_selectionRectangle);
+		}
+		
+		/**
+		 * Begin selection process
+		 */
+		public function startSelection(x : Number, y : Number) : void
+		{
+			_selectionRectangle.x = x;
+			_selectionRectangle.y = y;
+			_selectionRectangle.width = 0;
+			_selectionRectangle.height = 0;
+			this.visible = true;
+		}
+
+		/**
+		 * Update selection box bounds
+		 */
+		public function update(x : Number, y : Number) : void
+		{
+			_selectionRectangle.width = x - _selectionRectangle.x;
+			_selectionRectangle.height = y - _selectionRectangle.y;
+		}
+
+		/**
+		 * Finish selection process
+		 */
+		public function stopSelection() : void 
+		{
+			_selectionRectangle.width = 0;
+			_selectionRectangle.height = 0;
+			this.visible = false;
+		}
+
+		/**
+		 * If the box has width or height < 0 then move the point across the appropriate axis and change sign of property.
+		 */
+		private function normalize() : void
+		{
+			if (_selectionRectangle.width < 0)
+			{
+				_selectionRectangle.x += _selectionRectangle.width;
+				_selectionRectangle.width = -_selectionRectangle.width;
+			}
+			if (_selectionRectangle.height < 0)
+			{
+				_selectionRectangle.y += _selectionRectangle.height;
+				_selectionRectangle.height = -_selectionRectangle.height;
+			}
+		}
+
+		/**
+		 * Returns true if given point (x,y) is in bounds of selection points
+		 */
+		public function isInBounds(x : Number, y : Number) : Boolean
+		{
+			normalize();
+			if (x > _selectionRectangle.x &&
+				x < _selectionRectangle.x + _selectionRectangle.width &&
+				y > _selectionRectangle.y &&
+				y < _selectionRectangle.y + _selectionRectangle.height)
+				return true;
+			return false;
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/MainMenu.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/MainMenu.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/MainMenu.mxml	(revision 15)
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+<mx:Style source="/gssim/gssimstudio/editor/assets/css/mainMenu.css"/>
+<mx:Script>
+	<![CDATA[
+		import flexlib.mdi.containers.MDICanvas;
+		
+		import gssim.gssimstudio.editor.gssim.editors.TreeViewWindow;
+		import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+		import gssim.gssimstudio.editor.gssim.experiment.ExperimentProperties;
+		import gssim.gssimstudio.editor.gssim.topology.file.topologyReader;
+		import gssim.gssimstudio.editor.gssim.topology.file.topologyWriter;
+		import gssim.gssimstudio.editor.gssim.workload.WorkloadBasic;
+		import gssim.gssimstudio.editor.gssim.workload.file.workloadReader;
+		import gssim.gssimstudio.editor.gssim.workload.file.workloadWriter;
+		
+		import mx.controls.Alert;
+		
+		import gssim.gssimstudio.editor.script.command.DoNothing;
+		import gssim.gssimstudio.editor.script.command.OpenGeneralChartsWindowCommand;
+		import gssim.gssimstudio.editor.script.command.OpenMinimapWindowCommand;
+		import gssim.gssimstudio.editor.script.command.OpenToolboxWindowCommand;
+		import gssim.gssimstudio.editor.script.views.ViewsHelper;
+		
+		import gssim.gssimstudio.editor.views.ExperimentEditor;
+		import gssim.gssimstudio.editor.views.TopologyEditor;
+		import gssim.gssimstudio.editor.views.WorkloadEditor;
+	
+		private function newFile() : void
+		{
+			WorkloadEditor.workload = new WorkloadBasic();
+		}
+	
+		private function openFile() : void
+		{
+			var _workloadReader : workloadReader = new workloadReader();
+		}
+		
+		private function saveToFile() : void
+		{
+			//FIXME: very bad practice
+			if ((parent.parent.parent as WorkloadEditor).validateWorkload())
+			{
+				var _workloadWriter : workloadWriter = new workloadWriter();
+			}
+			else
+			{
+				Alert.show(resourceManager.getString('WorkloadEditor', 'InvalidWorkloadError'));
+			}
+		}
+		
+		private function showTreeView() : void
+		{
+			if ((parent.parent.parent as WorkloadEditor).validateWorkload())
+			{
+				var tree : TreeViewWindow = new TreeViewWindow();
+				ViewsHelper.WorkloadCanvas.windowManager.add(tree);
+			}
+			else
+			{
+				Alert.show(resourceManager.getString('WorkloadEditor', 'InvalidWorkloadError'));
+			}
+		}
+	]]>
+</mx:Script>
+	<mx:HBox horizontalGap="0">
+	<components:RollOutMenu width="100%" height="100%">
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" height="64" width="128" toolTip="{resourceManager.getString('WorkloadEditor', 'MenuTooltip')}"
+			label="{resourceManager.getString('WorkloadEditor', 'Menu')}"
+			iconUp="assets/icon/ShowIcons.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="newFile()" height="64" width="128" toolTip="{resourceManager.getString('WorkloadEditor', 'NewTooltip')}"
+			 label="{resourceManager.getString('WorkloadEditor', 'New')}"
+			 iconUp="assets/icon/NewFile.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="openFile()" height="64" width="128" toolTip="{resourceManager.getString('WorkloadEditor', 'OpenTooltip')}"
+			label="{resourceManager.getString('WorkloadEditor', 'Open')}"
+			iconUp="assets/icon/OpenFile.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="saveToFile()" height="64" width="128" toolTip="{resourceManager.getString('WorkloadEditor', 'SaveTooltip')}"
+			label="{resourceManager.getString('WorkloadEditor', 'Save')}"
+			iconUp="assets/icon/SaveFile.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="showTreeView()" height="64" width="128" toolTip="{resourceManager.getString('WorkloadEditor', 'ShowTooltip')}"
+			label="{resourceManager.getString('WorkloadEditor', 'Show')}"
+			iconUp="assets/icon/ShowTree.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="DoNothing(null)" height="64" width="128" toolTip="{resourceManager.getString('WorkloadEditor', 'GenerateTooltip')}"
+			label="{resourceManager.getString('WorkloadEditor', 'Generate')}"
+			iconUp="assets/infoButton.png"/>
+	</components:RollOutMenu>
+	</mx:HBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PreferencesWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PreferencesWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PreferencesWindow.mxml	(revision 15)
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="412" height="382" title="{resourceManager.getString('WorkloadEditor', 'Preferences')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.workload.PreferenceParameter;
+			import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+			import gssim.gssimstudio.editor.gssim.workload.Preference;
+			
+			[Bindable]
+			private var params : Preference;
+			
+			public function setParams(params : Preference) : void
+			{
+				this.params = params;
+				preferenceTypeInput.selectedItem = params.preferenceType;
+			}
+			
+			public function closeClick() : void
+			{
+				close();
+			}
+			
+			private function addPreferenceParameter() : void
+			{
+				params.preferenceParameters.addItem(new PreferenceParameter());
+			}
+			
+			public function removePreferenceParameter() : void
+			{
+				params.preferenceParameters.removeItemAt(dg.selectedIndex);
+			}
+			
+			public function editPreferenceParameter() : void
+			{
+				var winPar : PreferencesParameterWindow = new PreferencesParameterWindow();
+				windowManager.add(winPar);
+				winPar.setParams(dg.selectedItem as PreferenceParameter);
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5" width="100%">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'PreferenceType')}" width="150"/>
+			<mx:ComboBox id="preferenceTypeInput" dataProvider="{PreferenceType.getAsArray()}" width="110" change="params.preferenceType = preferenceTypeInput.selectedLabel"/>
+		</mx:HBox>
+		<mx:DataGrid dataProvider="{params.preferenceParameters}" rowHeight="35" id="dg" width="100%" >
+			<mx:columns>
+				<mx:DataGridColumn dataField="Name" headerText="{resourceManager.getString('WorkloadEditor', 'Name')}"/>
+				<mx:DataGridColumn dataField="Endpoint" headerText="{resourceManager.getString('WorkloadEditor', 'Endpoint')}"/>
+				<mx:DataGridColumn headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}">
+					<mx:itemRenderer>
+						<mx:Component>
+							<mx:HBox paddingLeft="4">
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="outerDocument.editPreferenceParameter()" height="30"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" click="outerDocument.removePreferenceParameter()" height="30"/>
+							</mx:HBox>
+						</mx:Component>
+					</mx:itemRenderer>
+				</mx:DataGridColumn>
+			</mx:columns>
+		</mx:DataGrid>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'AddNewPreferenceParameter')}" click="addPreferenceParameter()"/>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PreferencesParameterWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PreferencesParameterWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PreferencesParameterWindow.mxml	(revision 15)
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="296" height="206" title="{resourceManager.getString('WorkloadEditor', 'Preferences')} {resourceManager.getString('WorkloadEditor', 'Attributes')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.workload.PreferenceParameter;
+			import gssim.gssimstudio.editor.gssim.workload.types.OptimizationType;
+			import gssim.gssimstudio.editor.gssim.workload.RandParams;
+			
+			[Bindable]
+			private var params : PreferenceParameter
+			
+			public function setParams(params : PreferenceParameter) : void
+			{
+				this.params = params;
+				nameInput.text = params.Name;
+				endpointInput.text = params.Endpoint;
+				optimizationTypeInput.selectedItem = params.OptimizationType;
+			}
+			
+			public function closeClick() : void
+			{
+				close();
+			}
+			
+			private function openRandParamsWindow(par : RandParams, tag : String) : RandParams
+			{
+				var window : RandParamsWindow = new RandParamsWindow();
+				if (par == null) par = new RandParams("<" + tag + " />");
+				window.params = par;
+				windowManager.add(window);
+				return par;
+			}
+			
+			private function openImportanceRandParamsWindow(par : RandParams, tag : String) : void
+			{
+				params.Importance = openRandParamsWindow(par, tag);
+			}
+			
+			private function openValueRandParamsWindow(par : RandParams, tag : String) : void
+			{
+				params.Value = openRandParamsWindow(par, tag);
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Name')}" width="150"/>
+			<mx:TextInput id="nameInput" width="110" change="params.Name = nameInput.text"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Endpoint')}" width="150"/>
+			<mx:TextInput id="endpointInput" width="110" change="params.Endpoint = endpointInput.text"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Importance')}" width="150"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openImportanceRandParamsWindow(params.Importance, 'importance')"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="params.Importance = null;"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'OptimizationType')}" width="150"/>
+			<mx:ComboBox id="optimizationTypeInput" dataProvider="{OptimizationType.getAsArray()}" width="110" change="params.OptimizationType = optimizationTypeInput.selectedLabel"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Value')}" width="150"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openValueRandParamsWindow(params.Value, 'value')"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="params.Value = null;"/>
+		</mx:HBox>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PeriodicValuesDatePickWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PeriodicValuesDatePickWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/PeriodicValuesDatePickWindow.mxml	(revision 15)
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="320" height="130" title="{resourceManager.getString('WorkloadEditor', 'PeriodicValidValuesDates')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*"
+	close="saveValues()">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.workload.PeriodicValidValues;
+			
+			[Bindable]
+			private var params : PeriodicValidValues;
+			
+			public function setParams(params : PeriodicValidValues) : void
+			{
+				this.params = params;
+				begin.selectedDate = params.BeginValidTime;
+				end.selectedDate = params.EndValidTime;
+				beginTime.hour = params.BeginValidTime.hours;
+				beginTime.minute = params.BeginValidTime.minutes;
+				beginTime.second = params.BeginValidTime.seconds;
+				endTime.hour = params.EndValidTime.hours;
+				endTime.minute = params.EndValidTime.minutes;
+				endTime.second = params.EndValidTime.seconds;
+			}
+			
+			public function saveValues() : void
+			{
+				params.BeginValidTime.setHours(beginTime.hour, beginTime.minute, beginTime.second, 0);
+				params.EndValidTime.setHours(endTime.hour, endTime.minute, endTime.second, 0);
+			}
+			
+			public function closeClick() : void
+			{
+				close();
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'BeginDate')}" width="70"/>
+			<components:TimePicker id="beginTime" is24Hour="true" showSeconds="true"/>
+			<mx:DateField id="begin" change="params.BeginValidTime = begin.selectedDate"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'EndDate')}" width="70"/>
+			<components:TimePicker id="endTime" is24Hour="true" showSeconds="true" />
+			<mx:DateField id="end" change="params.EndValidTime = end.selectedDate" />
+		</mx:HBox>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/ParameterAttributesWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/ParameterAttributesWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/ParameterAttributesWindow.mxml	(revision 15)
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="298" height="254" title="{(params != null ? params.parentTagName : '')} {resourceManager.getString('WorkloadEditor', 'ProbabilisticParameters')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.workload.types.DistributionType;
+			import gssim.gssimstudio.editor.gssim.workload.ParameterAttributes;
+			import gssim.gssimstudio.editor.gssim.workload.Dist;
+			[Bindable]
+			private var params : ParameterAttributes;
+			
+			public function setParams(params : ParameterAttributes) : void
+			{
+				this.params = params;
+				idInput.text = params.Id;
+				refIdInput.text = params.RefElementId;
+				exprInput.text = params.Expr;
+				avgInput.text = params.Avg.toString().replace("NaN", "");
+				stDevInput.text = params.Stdev.toString().replace("NaN", "");
+				minInput.text = params.Min.toString().replace("NaN", "");
+				maxInput.text = params.Max.toString().replace("NaN", "");
+				seedInput.text = params.Seed.toString().replace("NaN", "");
+				distributionInput.selectedItem = params.Distribution;
+			}
+			
+			public function closeClick() : void
+			{
+				close();
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5">
+		<mx:TabNavigator paddingLeft="5" height="100%" width="100%" creationPolicy="all">
+			<mx:VBox label="{resourceManager.getString('WorkloadEditor', 'Basic')}">
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Average')}" width="150"/>
+					<mx:TextInput id="avgInput" width="110" change="params.Avg = (avgInput.text != '' ? Number(avgInput.text) : NaN)" restrict="0-9."/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'StandardDeviation')}" width="150"/>
+					<mx:TextInput id="stDevInput" width="110" change="params.Stdev = (stDevInput.text != '' ? Number(stDevInput.text) : NaN)" restrict="0-9."/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Minimum')}" width="150"/>
+					<mx:TextInput id="minInput" width="110" change="params.Min = (minInput.text != '' ? Number(minInput.text) : NaN)" restrict="0-9."/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Maximum')}" width="150"/>
+					<mx:TextInput id="maxInput" width="110" change="params.Max = (maxInput.text != '' ? Number(maxInput.text) : NaN)" restrict="0-9."/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Distribution')}" width="150"/>
+					<mx:ComboBox id="distributionInput" dataProvider="{DistributionType.getAsArray()}" width="110" change="params.Distribution = distributionInput.selectedLabel"/>
+				</mx:HBox>
+			</mx:VBox>
+			<mx:VBox label="{resourceManager.getString('WorkloadEditor', 'Dependencies')}">
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'ID')}" width="150"/>
+					<mx:TextInput id="idInput" width="110" change="params.Id = idInput.text"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'ReferenceID')}" width="150"/>
+					<mx:TextInput id="refIdInput" width="110" change="params.RefElementId = refIdInput.text"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Expression')}" width="150"/>
+					<mx:TextInput id="exprInput" width="110" change="params.Expr = exprInput.text"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('WorkloadEditor', 'RandomSeed')}" width="150"/>
+					<mx:TextInput id="seedInput" width="110" change="params.Seed = (seedInput.text != '' ? Number(seedInput.text) : NaN)" restrict="0-9."/>
+				</mx:HBox>
+			</mx:VBox>
+		</mx:TabNavigator>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/RandParamsWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/RandParamsWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/RandParamsWindow.mxml	(revision 15)
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" title="{paramName}" width="700" height="372">
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.gssim.workload.PeriodicValidValues;
+		import gssim.gssimstudio.editor.views.WorkloadEditor;
+		import gssim.gssimstudio.editor.gssim.workload.WorkloadBasic;
+		import gssim.gssimstudio.editor.gssim.workload.RandParams;
+		import gssim.gssimstudio.editor.gssim.workload.ParameterAttributes;
+		
+		[Bindable]
+		private var _params : RandParams;
+		
+		public function get params() : RandParams
+		{
+			return _params;
+		}
+		
+		public function set params(value : RandParams) : void
+		{
+			_params = value;
+			if (_params != null && _params.params != null) paramName = _params.params.parentTagName;
+		}
+		
+		[Bindable]
+		private var paramName : String;
+		
+		public function init(paramName : String) : void
+		{
+			this.paramName = paramName;
+			_params = WorkloadEditor.workload.getProperty(paramName) as RandParams;
+			if (_params == null) _params = new RandParams(paramName);
+			WorkloadEditor.workload.setProperty(paramName, params);
+		}
+		
+		private function editAttributes() : void
+		{
+			var winPar : ParameterAttributesWindow = new ParameterAttributesWindow();
+			windowManager.add(winPar);
+			winPar.setParams(params.params);
+		}
+		
+		private function editMultiDistribution() : void
+		{
+			var winPar : MultiDistributionWindow = new MultiDistributionWindow();
+			windowManager.add(winPar);
+			winPar.setParams(paramName, _params);
+		}
+		
+		private function clearMultiDistribution() : void
+		{
+			_params.multiDist = null;
+		}
+		
+		public function closeClick() : void
+		{
+			close();
+		}
+		
+		private function addPeriodic() : void
+		{
+			_params.periodicValidValues.addItem(new PeriodicValidValues());
+		}
+		
+		public function removePeriodic() : void
+		{
+			_params.periodicValidValues.removeItemAt(dg.selectedIndex);
+		}
+		
+		public function editPeriodic() : void
+		{
+			var winPar : PeriodicValuesDatePickWindow = new PeriodicValuesDatePickWindow();
+			windowManager.add(winPar);
+			winPar.setParams(dg.selectedItem as PeriodicValidValues);
+		}
+		
+		public function editAttrPeriodic() : void
+		{
+			var winPar : ParameterAttributesWindow = new ParameterAttributesWindow();
+			windowManager.add(winPar);
+			winPar.setParams(dg.selectedItem.params);
+		}
+	]]>
+</mx:Script>
+<mx:HBox>
+	<mx:Button label="{resourceManager.getString('WorkloadEditor', 'ProbabilisticParameters')}" click="editAttributes()"/>
+	<mx:Button label="{resourceManager.getString('WorkloadEditor', 'MultiDistribution')}" click="editMultiDistribution()"/>
+	<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')} {resourceManager.getString('WorkloadEditor', 'MultiDistribution')}" click="clearMultiDistribution()"/>
+</mx:HBox>
+<mx:DataGrid dataProvider="{_params.periodicValidValues}" rowHeight="35" id="dg" width="100%" >
+	<mx:columns>
+		<mx:DataGridColumn dataField="BeginValidTime" headerText="{resourceManager.getString('WorkloadEditor', 'BeginTime')}"/>
+		<mx:DataGridColumn dataField="EndValidTime" headerText="{resourceManager.getString('WorkloadEditor', 'EndTime')}"/>
+		<mx:DataGridColumn headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}">
+			<mx:itemRenderer>
+				<mx:Component>
+					<mx:HBox paddingLeft="4">
+						<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="outerDocument.editAttrPeriodic()" height="30" paddingLeft="8"/>
+						<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Dates')}" click="outerDocument.editPeriodic()" height="30"/>
+						<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" click="outerDocument.removePeriodic()" height="30"/>
+					</mx:HBox>
+				</mx:Component>
+			</mx:itemRenderer>
+		</mx:DataGridColumn>
+	</mx:columns>
+</mx:DataGrid>
+<mx:Button label="{resourceManager.getString('WorkloadEditor', 'AddNewPeriod')}" click="addPeriodic()"/>
+<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DataGridCHRPButtonsRenderer.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DataGridCHRPButtonsRenderer.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DataGridCHRPButtonsRenderer.mxml	(revision 15)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.views.WorkloadEditor;
+		import gssim.gssimstudio.editor.script.views.ViewsHelper;
+		import gssim.gssimstudio.editor.gssim.workload.ComputingResourceHostParameter;
+		import gssim.gssimstudio.editor.gssim.editors.workload.ComputingResourceHostParameterWindow;
+		
+		private function openComputingResourceHostParameterWindow() : void
+		{
+			var window : ComputingResourceHostParameterWindow = new ComputingResourceHostParameterWindow();
+			ViewsHelper.WorkloadCanvas.windowManager.add(window);
+			window.crhp = data as ComputingResourceHostParameter;
+		}
+		
+		private function removeItem() : void
+		{
+			WorkloadEditor.workload.CRHP.removeItemAt(WorkloadEditor.workload.CRHP.getItemIndex(data));
+		}
+	]]>
+</mx:Script>
+	<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" height="30" click="openComputingResourceHostParameterWindow()"/>
+	<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" height="30" click="removeItem()"/>
+</mx:HBox>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/MultiDistributionWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/MultiDistributionWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/MultiDistributionWindow.mxml	(revision 15)
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml"
+	width="90%" title="{tagName} MultiDistribution" close="saveChanges()">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.workload.RandParams;
+			import gssim.gssimstudio.editor.gssim.workload.MultiDistribution;
+			import mx.binding.utils.BindingUtils;
+			import mx.collections.ArrayCollection;
+			import gssim.gssimstudio.editor.gssim.workload.Dist;
+			import gssim.gssimstudio.editor.gssim.workload.ParameterAttributes;
+			
+			public var dist : MultiDistribution;
+			private var params : RandParams;
+			[Bindable]
+			private var tagName : String;
+			
+			public function setParams(tagName : String, params : RandParams) : void
+			{
+				this.tagName = tagName;
+				if (params.multiDist == null) params.multiDist = new MultiDistribution();
+				dist = params.multiDist.clone();
+				loadDistributionVisual();
+				this.params = params;
+			}
+			
+			private function loadDistributionVisual() : void
+			{
+				hd.removeAllChildren();
+				for each (var di : Dist in dist.Distributions)
+				{
+					var l : DistVisual = new DistVisual();
+					l.dist = di;
+					l.percentWidth = di.Probability * 100;
+					hd.addChild(l);
+					l.remove.addEventListener(MouseEvent.CLICK, removeItemClick);
+				}
+				hd.validateProperties();
+				hd.validateSize();
+				hd.validateDisplayList();
+				updateMD();
+			}
+			
+			private function addNewDist() : void
+			{
+				var d : Dist = new Dist("MultiDistribution");
+				dist.addDist(d, 0);
+				var l : DistVisual = new DistVisual();
+				l.dist = d;
+				hd.addChild(l);
+				hd.validateDisplayList();
+				l.remove.addEventListener(MouseEvent.CLICK, removeItemClick);
+				updateMD();
+			}
+			
+			private function removeItemClick(event : Event) : void
+			{
+				var target : DistVisual = event.target.parent as DistVisual;
+				dist.removeDist(hd.getChildIndex(target));
+				hd.removeChild(target);
+				hd.validateDisplayList();
+				updateMD();
+			}
+			
+			private function updateMD() : void
+			{
+				var sum : Number = 0;
+				for (var j : Number = 0; j < hd.getChildren().length; j++)
+				{
+					sum += hd.getChildAt(j).width;
+				}
+				var checkSum : Number = 0;
+				for (var i : Number = 0; i < hd.getChildren().length; i++)
+				{
+					var prob : Number = hd.getChildAt(i).width / sum;
+					prob = Number(twoAfterDot.format(prob));
+					checkSum += prob;
+					if (i == hd.getChildren().length - 1)
+					{
+						prob = prob + (1-checkSum);
+						prob = Number(twoAfterDot.format(prob));
+					} 
+					dist.updateDist(i, prob);
+					(hd.getChildAt(i) as DistVisual).probability = prob;
+				}
+			}
+			
+			public function saveChanges() : void
+			{
+				params.multiDist = dist;
+			}
+			
+			public function closeClick() : void
+			{
+				close();
+			}
+		]]>
+	</mx:Script>
+	<mx:NumberFormatter id="twoAfterDot" precision="4" rounding="nearest"/>
+	<mx:Canvas width="100%" >
+	<mx:VBox width="100%" >
+		<mx:HDividedBox width="100%" id="hd" height="76" liveDragging="true" dividerRelease="updateMD()" dividerDrag="updateMD()" />
+		<mx:Button id="addNewDistButton" label="{resourceManager.getString('WorkloadEditor', 'AddNewDist')}" click="addNewDist()"/>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/> 
+	</mx:VBox>
+	</mx:Canvas>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/ComputingResourceHostParameterWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/ComputingResourceHostParameterWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/ComputingResourceHostParameterWindow.mxml	(revision 15)
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" height="180">
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.gssim.workload.types.Metric;
+		import gssim.gssimstudio.editor.gssim.workload.ComputingResourceHostParameter;
+		import gssim.gssimstudio.editor.gssim.workload.RandParams;
+		
+		[Bindable]
+		private var _crhp : ComputingResourceHostParameter;
+		
+		public function set crhp(value : ComputingResourceHostParameter) : void
+		{
+			metricInput.selectedItem = value.metric;
+			_crhp = value;
+			this.title = _crhp.value.params.Id;
+		}
+	
+		private function openRandParamsWindow(par : RandParams, tag : String) : RandParams
+		{
+			var window : RandParamsWindow = new RandParamsWindow();
+			if (par == null) par = new RandParams("<" + tag + " />");
+			window.params = par;
+			windowManager.add(window);
+			return par;
+		}
+		
+		private function openMinRandParamsWindow(par : RandParams, tag : String) : void
+		{
+			_crhp.range.min = openRandParamsWindow(par, tag);
+		}
+		
+		private function openMaxRandParamsWindow(par : RandParams, tag : String) : void
+		{
+			_crhp.range.max = openRandParamsWindow(par, tag);
+		}
+		
+		public function closeClick() : void
+		{
+			close();
+		}
+	]]>
+</mx:Script>
+	<mx:VBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Metric')}" width="55"/>
+			<mx:ComboBox id="metricInput" dataProvider="{Metric.getAsArray()}" width="120" change="_crhp.metric = metricInput.selectedLabel"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Value')}" width="65"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(_crhp.value, 'value')"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="_crhp.value = null;"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Minimum')}" width="65"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openMinRandParamsWindow(_crhp.range.min, 'min')"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="_crhp.range.min = null;"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Maximum')}" width="65"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openMaxRandParamsWindow(_crhp.range.max, 'max')"/>
+			<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="_crhp.range.max = null;"/>
+		</mx:HBox>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DataGridPrefsButtonsRenderer.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DataGridPrefsButtonsRenderer.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DataGridPrefsButtonsRenderer.mxml	(revision 15)
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.gssim.workload.Preference;
+		import gssim.gssimstudio.editor.views.WorkloadEditor;
+		import gssim.gssimstudio.editor.script.views.ViewsHelper;
+		import gssim.gssimstudio.editor.gssim.workload.ComputingResourceHostParameter;
+		import gssim.gssimstudio.editor.gssim.editors.workload.ComputingResourceHostParameterWindow;
+		
+		private function OpenPreferenceWindow() : void
+		{
+			var window : PreferencesWindow = new PreferencesWindow();
+			ViewsHelper.WorkloadCanvas.windowManager.add(window);
+			window.setParams(data as Preference);
+		}
+		
+		private function removeItem() : void
+		{
+			WorkloadEditor.workload.Prefs.removeItemAt(WorkloadEditor.workload.Prefs.getItemIndex(data));
+		}
+	]]>
+</mx:Script>
+	<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" height="30" click="OpenPreferenceWindow()"/>
+	<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" height="30" click="removeItem()"/>
+</mx:HBox>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DistVisual.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DistVisual.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/workload/DistVisual.mxml	(revision 15)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" minWidth="75" width="100%" verticalGap="0">
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.script.views.ViewsHelper;
+		import flexlib.mdi.managers.MDIManager;
+		import gssim.gssimstudio.editor.gssim.workload.ParameterAttributes;
+		import gssim.gssimstudio.editor.gssim.workload.Dist;
+		[Bindable]
+		public var probability : Number;
+		public var dist : Dist;
+		
+		public function edit() : void
+		{
+			var winPar : ParameterAttributesWindow = new ParameterAttributesWindow();
+			ViewsHelper.WorkloadCanvas.windowManager.add(winPar);
+			winPar.setParams(dist);
+		}
+	]]>
+</mx:Script>
+	<mx:NumberFormatter id="twoAfterDot" precision="2" rounding="nearest"/>
+	<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" width="100%" styleName="flatButton" click="edit();"/>
+	<mx:Button id="remove" label="{resourceManager.getString('WorkloadEditor', 'Remove')}" width="100%" styleName="flatButton"/>
+	<mx:Label text="{twoAfterDot.format(probability * 100)}%" textAlign="center" width="100%"/>
+</mx:VBox>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/ComputingResourceWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/ComputingResourceWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/ComputingResourceWindow.mxml	(revision 15)
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Computing resources can be defined using this window.
+-->
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="427" height="507" title="{resourceManager.getString('ResourceEditor', 'ComputingResource')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*" xmlns:resources="gssim.gssimstudio.editor.gssim.editors.resources.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.resources.ComputingResource;
+			import gssim.gssimstudio.editor.gssim.resources.HostParameter;
+			import gssim.gssimstudio.editor.gssim.resources.OtherParameter;
+			import gssim.gssimstudio.editor.gssim.resources.types.HostParameterType;
+			
+			[Bindable]
+			private var params : ComputingResource;
+			
+			public function setParams(params : ComputingResource, disableEdit : Boolean = false) : void
+			{
+				this.params = params;
+				resourceIdInput.text = params.resourceId;
+				if (disableEdit)
+				{
+					resourceIdInput.editable = false;
+					countBox.visible = false;
+					countInput.enabled = false;
+					countBox.includeInLayout = false;
+				}
+			}
+			
+			public function closeClick() : void
+			{
+				close();
+			}
+			
+			private function addHostParameter() : void
+			{
+				params.hostParameters.addItem(new HostParameter());
+			}
+			
+			public function removeHostParameter() : void
+			{
+				params.hostParameters.removeItemAt(dg.selectedIndex);
+			}
+			
+			public function editHostParameter() : void
+			{
+				var winPar : HostParameterWindow = new HostParameterWindow();
+				windowManager.add(winPar);
+				winPar.setParams(dg.selectedItem as HostParameter);
+			}
+			
+			private function addOtherParameter() : void
+			{
+				params.otherParameters.addItem(new OtherParameter());
+			}
+			
+			public function removeOtherParameter() : void
+			{
+				params.otherParameters.removeItemAt(dg2.selectedIndex);
+			}
+			
+			public function editOtherParameter() : void
+			{
+				otherParamEdit.setParams(dg2.selectedItem as OtherParameter);
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5" width="100%">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('ResourceEditor', 'ResourceId')}" width="150"/>
+			<mx:TextInput id="resourceIdInput" width="110" change="params.resourceId = resourceIdInput.text"/>
+		</mx:HBox>
+		<mx:HBox id="countBox">
+			<mx:Label text="{resourceManager.getString('TopologyEditor', 'Count')}" width="140"/>
+			<mx:NumericStepper id="countInput" width="150" value="{params.count}" change="params.count = countInput.value" maximum="10000"/>
+		</mx:HBox>
+		<mx:TabNavigator width="100%" height="400">
+			<mx:VBox width="100%" label="{resourceManager.getString('ResourceEditor', 'HostParameter')}">
+				<mx:DataGrid dataProvider="{params.hostParameters}" rowHeight="35" id="dg" width="100%" >
+					<mx:columns>
+						<mx:DataGridColumn dataField="hostParameterType" headerText="{resourceManager.getString('WorkloadEditor', 'Name')}"/>
+						<mx:DataGridColumn dataField="hostParameterParamValue" headerText="{resourceManager.getString('WorkloadEditor', 'Value')}"/>
+						<mx:DataGridColumn headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}">
+							<mx:itemRenderer>
+								<mx:Component>
+									<mx:HBox paddingLeft="4">
+										<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="outerDocument.editHostParameter()" height="30"/>
+										<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" click="outerDocument.removeHostParameter()" height="30"/>
+									</mx:HBox>
+								</mx:Component>
+							</mx:itemRenderer>
+						</mx:DataGridColumn>
+					</mx:columns>
+				</mx:DataGrid>
+				<mx:Button label="{resourceManager.getString('ResourceEditor', 'AddNewHostParameter')}" click="addHostParameter()"/>
+			</mx:VBox>
+			<mx:VBox width="100%" label="{resourceManager.getString('ResourceEditor', 'OtherParameter')}">
+				<mx:Button label="{resourceManager.getString('ResourceEditor', 'AddNewOtherParameter')}" click="addOtherParameter()"/>
+				<mx:DataGrid dataProvider="{params.otherParameters}" rowHeight="35" id="dg2" width="100%" >
+					<mx:columns>
+						<mx:DataGridColumn dataField="otherParameterType" headerText="{resourceManager.getString('WorkloadEditor', 'Name')}"/>
+						<mx:DataGridColumn dataField="otherParameterValue" headerText="{resourceManager.getString('WorkloadEditor', 'Value')}"/>
+						<mx:DataGridColumn headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}">
+							<mx:itemRenderer>
+								<mx:Component>
+									<mx:HBox paddingLeft="4">
+										<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="outerDocument.editOtherParameter()" height="30"/>
+										<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" click="outerDocument.removeOtherParameter()" height="30"/>
+									</mx:HBox>
+								</mx:Component>
+							</mx:itemRenderer>
+						</mx:DataGridColumn>
+					</mx:columns>
+				</mx:DataGrid>
+				<resources:OtherParameterEdit id="otherParamEdit"/>
+			</mx:VBox>
+		</mx:TabNavigator>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/HostParameterWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/HostParameterWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/HostParameterWindow.mxml	(revision 15)
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Host parameters can be defined using this window.
+-->
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="412" height="462" title="{resourceManager.getString('ResourceEditor', 'HostParameter')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*" xmlns:resources="gssim.gssimstudio.editor.gssim.editors.resources.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.resources.HostParameter;
+			import gssim.gssimstudio.editor.gssim.resources.Property;
+			import gssim.gssimstudio.editor.gssim.resources.types.HostParameterType;
+			
+			[Bindable]
+			private var params : HostParameter;
+			
+			public function setParams(params : HostParameter) : void
+			{
+				this.params = params;
+				parameterTypeInput.selectedItem = params.hostParameterType;
+				parameterValueInput.text = params.hostParameterParamValue;
+			}
+			
+			public function closeClick() : void
+			{
+				close();
+			}
+			
+			private function addProperty() : void
+			{
+				params.properties.addItem(new Property());
+			}
+			
+			public function removeProperty() : void
+			{
+				params.properties.removeItemAt(dg.selectedIndex);
+			}
+			
+			public function editProperty() : void
+			{
+				propertyEdit.setParams(dg.selectedItem as Property);
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5" width="100%">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('ResourceEditor', 'ParameterType')}" width="150"/>
+			<mx:ComboBox id="parameterTypeInput" dataProvider="{HostParameterType.getAsArray()}" width="110" change="params.hostParameterType = parameterTypeInput.selectedLabel"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Value')}" width="150"/>
+			<mx:TextInput id="parameterValueInput" width="110" change="params.hostParameterParamValue = parameterValueInput.text"/>
+		</mx:HBox>
+		<mx:Button label="{resourceManager.getString('ResourceEditor', 'AddNewProperty')}" click="addProperty()"/>
+		<mx:DataGrid dataProvider="{params.properties}" rowHeight="35" id="dg" width="100%" >
+			<mx:columns>
+				<mx:DataGridColumn dataField="propertyType" headerText="{resourceManager.getString('WorkloadEditor', 'Name')}"/>
+				<mx:DataGridColumn dataField="propertyValue" headerText="{resourceManager.getString('WorkloadEditor', 'Value')}"/>
+				<mx:DataGridColumn headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}">
+					<mx:itemRenderer>
+						<mx:Component>
+							<mx:HBox paddingLeft="4">
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="outerDocument.editProperty()" height="30"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" click="outerDocument.removeProperty()" height="30"/>
+							</mx:HBox>
+						</mx:Component>
+					</mx:itemRenderer>
+				</mx:DataGridColumn>
+			</mx:columns>
+		</mx:DataGrid>
+		<resources:PropertyEdit id="propertyEdit"/>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/OtherParameterEdit.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/OtherParameterEdit.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/OtherParameterEdit.mxml	(revision 15)
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Other parameters can be defined using this component
+-->
+<mx:Canvas xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" enabled="false" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.resources.OtherParameter;
+			import gssim.gssimstudio.editor.gssim.resources.types.OtherParameterType;
+			
+			[Bindable]
+			private var params : OtherParameter;
+			
+			public function setParams(params : OtherParameter) : void
+			{
+				this.params = params;
+				parameterTypeInput.selectedItem = params.otherParameterType;
+				parameterValueInput.text = params.otherParameterValue;
+				this.enabled=true;
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5" width="100%">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('ResourceEditor', 'ParameterType')}" width="150"/>
+			<mx:ComboBox id="parameterTypeInput" dataProvider="{OtherParameterType.getAsArray()}" width="110" change="params.otherParameterType = parameterTypeInput.selectedLabel"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Value')}" width="150"/>
+			<mx:TextInput id="parameterValueInput" width="110" change="params.otherParameterValue = parameterValueInput.text"/>
+		</mx:HBox>
+	</mx:VBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/PropertyEdit.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/PropertyEdit.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/PropertyEdit.mxml	(revision 15)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Properties can be defined using this component.
+-->
+<mx:Canvas xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:components="gssim.gssimstudio.editor.gssim.components.*" enabled="false">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.resources.Property;
+			import gssim.gssimstudio.editor.gssim.resources.types.PropertyType;
+			import gssim.gssimstudio.editor.gssim.workload.PreferenceParameter;
+			import gssim.gssimstudio.editor.gssim.workload.RandParams;
+			import gssim.gssimstudio.editor.gssim.workload.types.OptimizationType;
+			
+			[Bindable]
+			private var property : Property
+			
+			/**
+			 * Sets the binding for given property and displays the component in GUI.
+			 */
+			public function setParams(property : Property) : void
+			{
+				this.property = property;
+				propertyValueInput.text = property.propertyValue;
+				propertyTypeInput.selectedItem = property.propertyType;
+				this.enabled = true;
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('ResourceEditor', 'PropertyType')}" width="150"/>
+			<mx:ComboBox id="propertyTypeInput" dataProvider="{PropertyType.getAsArray()}" width="110" change="property.propertyType = propertyTypeInput.selectedLabel"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Value')}" width="150"/>
+			<mx:TextInput id="propertyValueInput" width="110" change="property.propertyValue = propertyValueInput.text"/>
+		</mx:HBox>
+	</mx:VBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/QueueParameterEdit.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/QueueParameterEdit.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/QueueParameterEdit.mxml	(revision 15)
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Queue parameters can be defined using this component.
+-->
+<mx:Canvas xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" enabled="false" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.resources.QueueParameter;
+			import gssim.gssimstudio.editor.gssim.resources.types.QueueParameterType;
+			
+			[Bindable]
+			private var params : QueueParameter;
+			
+			public function setParams(params : QueueParameter) : void
+			{
+				this.params = params;
+				parameterTypeInput.selectedItem = params.queueParameterType;
+				parameterValueInput.text = params.queueParameterValue;
+				this.enabled = true;
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5" width="100%">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('ResourceEditor', 'ParameterType')}" width="150"/>
+			<mx:ComboBox id="parameterTypeInput" dataProvider="{QueueParameterType.getAsArray()}" width="110" change="params.queueParameterType = parameterTypeInput.selectedLabel"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('WorkloadEditor', 'Value')}" width="150"/>
+			<mx:TextInput id="parameterValueInput" width="110" change="params.queueParameterValue = parameterValueInput.text"/>
+		</mx:HBox>
+	</mx:VBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/QueueResourceWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/QueueResourceWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/resources/QueueResourceWindow.mxml	(revision 15)
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Queue resources can be defined using this window.
+-->
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="412" height="462" title="{resourceManager.getString('ResourceEditor', 'ComputingResource')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*" xmlns:resources="gssim.gssimstudio.editor.gssim.editors.resources.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.resources.OtherParameter;
+			import gssim.gssimstudio.editor.gssim.resources.QueueParameter;
+			import gssim.gssimstudio.editor.gssim.resources.QueueResource;
+			
+			[Bindable]
+			private var params : QueueResource;
+			
+			public function setParams(params : QueueResource) : void
+			{
+				this.params = params;
+				resourceIdInput.text = params.resourceId;
+			}
+			
+			public function closeClick() : void
+			{
+				close();
+			}
+			
+			private function addQueueParameter() : void
+			{
+				params.queueParameters.addItem(new QueueParameter());
+			}
+			
+			public function removeQueueParameter() : void
+			{
+				params.queueParameters.removeItemAt(dg.selectedIndex);
+			}
+			
+			public function editQueueParameter() : void
+			{
+				paramEdit.setParams(dg.selectedItem as QueueParameter);
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox paddingLeft="5" paddingTop="5" width="100%">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('ResourceEditor', 'ResourceId')}" width="150"/>
+			<mx:TextInput id="resourceIdInput" width="110" change="params.resourceId = resourceIdInput.text" editable="false"/>
+		</mx:HBox>
+		<mx:Button label="{resourceManager.getString('ResourceEditor', 'AddNewQueueParameter')}" click="addQueueParameter()"/>
+		<mx:DataGrid dataProvider="{params.queueParameters}" rowHeight="35" id="dg" width="100%" >
+			<mx:columns>
+				<mx:DataGridColumn dataField="queueParameterType" headerText="{resourceManager.getString('WorkloadEditor', 'Name')}"/>
+				<mx:DataGridColumn dataField="queueParameterValue" headerText="{resourceManager.getString('WorkloadEditor', 'Value')}"/>
+				<mx:DataGridColumn headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}">
+					<mx:itemRenderer>
+						<mx:Component>
+							<mx:HBox paddingLeft="4">
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="outerDocument.editQueueParameter()" height="30"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" click="outerDocument.removeQueueParameter()" height="30"/>
+							</mx:HBox>
+						</mx:Component>
+					</mx:itemRenderer>
+				</mx:DataGridColumn>
+			</mx:columns>
+		</mx:DataGrid>
+		<resources:QueueParameterEdit id="paramEdit"/>
+		<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Close')}" click="closeClick();"/>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/chartWindows/TasksGanttChart.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/chartWindows/TasksGanttChart.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/chartWindows/TasksGanttChart.mxml	(revision 15)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ObjectParamsWindow 
+	xmlns="gssim.gssimstudio.editor.gssim.editors.topology.*" 
+	xmlns:mx="http://www.adobe.com/2006/mxml" 
+	xmlns:c="gssim.gssimstudio.editor.charts.*"
+	
+	title="Tasks Gantt Chart"
+ 	width="700"
+  	height="360" 
+  	minWidth="700" 
+   	minHeight="360"
+   	horizontalScrollPolicy="off" 
+   	verticalScrollPolicy="off"
+>
+	<c:ScheduleViewer id="scheduleViewer" width="100%" height="100%"/>
+</ObjectParamsWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/chartWindows/ResourcesChart.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/chartWindows/ResourcesChart.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/chartWindows/ResourcesChart.mxml	(revision 15)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ObjectParamsWindow 
+	xmlns="gssim.gssimstudio.editor.gssim.editors.topology.*" 
+	xmlns:mx="http://www.adobe.com/2006/mxml" 
+	xmlns:c="gssim.gssimstudio.editor.charts.*"
+	
+	title="Resources Area Chart"
+ 	width="740"
+  	height="440" 
+  	minWidth="740" 
+   	minHeight="440"
+   	horizontalScrollPolicy="off" 
+   	verticalScrollPolicy="off" 
+>
+	<c:ResourceChart id="resourceViewer" width="100%" height="100%"/>
+</ObjectParamsWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/LinkPropertiesWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/LinkPropertiesWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/LinkPropertiesWindow.mxml	(revision 15)
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindow xmlns="flexlib.mdi.containers.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="310" height="210"
+	creationComplete="fillFields();" maxWidth="320" maxHeight="220" resizable="false">
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.gssim.topology.NetworkObjectLinker;
+		import mx.controls.Alert;
+		
+		private var _link : NetworkObjectLinker;
+		
+		public function init(link : NetworkObjectLinker) : void
+		{
+			_link = link;
+			title = _link.id;
+			name = title;
+			_link.addEventListener(gssim.gssimstudio.editor.gssim.topology.NetworkObjectLinker.CHANGE, linkChangedEventHandler);
+		}
+		
+		private function linkChangedEventHandler(event : Event) : void
+		{
+			NameInput.text = _link.id;
+			title = _link.id;
+			name = _link.id;
+		}
+		
+		private function fillFields() : void
+		{
+			if (_link == null) return;
+			NameInput.text = _link.id;
+			BaudRateInput.text = _link.BaudRate.toString();
+			WorkloadInput.text = _link.UsedBaudRate.toString();
+			PropDelayInput.text = _link.PropDelay.toString();
+			MTUInput.text = _link.MTU.toString();
+		}
+		
+		private function saveCloseClick() : void
+		{
+			var oldID : String = _link.id;
+			var oldBaudRate : Number = _link.BaudRate;
+			var oldUsedBaudRate : Number = _link.UsedBaudRate;
+			var oldPropDelay : Number = _link.PropDelay;
+			var oldMTU : Number = _link.MTU;
+			try
+			{
+				_link.id = NameInput.text;
+				_link.BaudRate = Number(BaudRateInput.text);
+				_link.UsedBaudRate = Number(WorkloadInput.text);
+				_link.PropDelay = Number(PropDelayInput.text);
+				_link.MTU = Number(MTUInput.text);
+			}
+			catch (error : Error)
+			{
+				_link.id = oldID;
+				_link.BaudRate = oldBaudRate;
+				_link.UsedBaudRate = oldUsedBaudRate;
+				_link.PropDelay = oldPropDelay;
+				_link.MTU = oldMTU;
+				Alert.show(resourceManager.getString('TopologyEditor', 'InvalidDataInField'));
+				return;
+			}
+			close();
+		}
+		
+	]]>
+</mx:Script>
+	<mx:VBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('TopologyEditor', 'Name')}" width="140"/>
+			<mx:TextInput id="NameInput" width="150" enabled="false"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('TopologyEditor', 'BaudRate')} (GB/s)" width="140"/>
+			<mx:TextInput id="BaudRateInput" width="150" restrict=".0-9"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('TopologyEditor', 'Workload')} (GB/s)" width="140"/>
+			<mx:TextInput id="WorkloadInput" width="150" restrict=".0-9"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('TopologyEditor', 'PropagationDelay')} (ms)" width="140"/>
+			<mx:TextInput id="PropDelayInput" width="150" restrict=".0-9"/>
+		</mx:HBox>
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('TopologyEditor', 'MTU')} (bytes)" width="140"/>
+			<mx:TextInput id="MTUInput" width="150" restrict=".0-9"/>
+		</mx:HBox>
+		<mx:Button label="{resourceManager.getString('TopologyEditor', 'SaveClose')}" click="saveCloseClick();"/>
+	</mx:VBox>
+</MDIWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/MinimapWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/MinimapWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/MinimapWindow.mxml	(revision 15)
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	This window contains the minimap for network topology. Allows to move the main screen and zoom in/out.
+-->
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="306" height="357"
+	xmlns:minimap="gssim.gssimstudio.editor.gssim.minimap.*" title="{resourceManager.getString('TopologyEditor', 'Minimap')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.gssim.skins.IconButtonSkin;
+		import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+		
+		import mx.core.Application;
+		import mx.core.FlexGlobals;
+		
+		import gssim.gssimstudio.editor.script.command.ApplyZoomCommand;
+		
+		//used for zooming functionality
+		private var objectCanvas : ObjectCanvas;
+		
+		public function UpdateObject(object : GenderObject, wasDeleted : Boolean = false) : void
+		{
+			minimap.UpdateObject(object, wasDeleted);
+		}
+		
+		public function clean() : void
+		{
+			minimap.clean();
+		}
+		
+		public function scale() : void
+		{
+			minimap.scaleChanged();
+		}
+		
+		public function init(target : ObjectCanvas) : void 
+		{
+			objectCanvas = target;
+			minimap.init(target);
+			//hack for proper placement of minimap window in bottom right corner
+			originalX = parentApplication.width - width;
+			originalY = parentApplication.height - height;
+		}
+		
+		private function zoomIn() : void
+		{
+			var k : ApplyZoomCommand = new ApplyZoomCommand(objectCanvas, 1, FlexGlobals.topLevelApplication.screen.width/2, FlexGlobals.topLevelApplication.screen.height/2);
+			k.execute();
+		}
+		
+		private function zoomOut() : void
+		{
+			var k : ApplyZoomCommand = new ApplyZoomCommand(objectCanvas, -1, FlexGlobals.topLevelApplication.screen.width/2, FlexGlobals.topLevelApplication.screen.height/2);
+			k.execute();
+		}
+		
+	]]>
+</mx:Script>
+	<mx:VBox backgroundColor="#FFFFFF" verticalGap="0">
+		<mx:HBox width="100%" horizontalGap="0">
+			<components:IconButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin" label="{resourceManager.getString('TopologyEditor', 'ZoomIn')}"
+								   width="50%" autoRepeat="true" buttonDown="zoomIn();" iconUp="assets/icon/ZoomIn.png"/>
+			<components:IconButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin" label="{resourceManager.getString('TopologyEditor', 'ZoomOut')}"
+								   width="50%" autoRepeat="true" buttonDown="zoomOut();" iconUp="assets/icon/ZoomOut.png"/>
+		</mx:HBox>
+		<minimap:Minimap id="minimap" width="300" height="300">
+			
+		</minimap:Minimap>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectCanvas.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectCanvas.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectCanvas.mxml	(revision 15)
@@ -0,0 +1,540 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Main canvas on which network items are placed. Graph property stores the representation of the topology.
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init();" xmlns:degrafa="http://www.degrafa.com/2007" xmlns:code="http://code.google.com/p/flexlib/"
+	backgroundColor="Black" backgroundAlpha="0" xmlns:local="*" xmlns:minimap="gssim.gssimstudio.editor.gssim.minimap.*">
+	<mx:Script>
+		<![CDATA[
+			import com.degrafa.GeometryComposition;
+			import com.degrafa.core.utils.ColorKeys;
+			import com.degrafa.geometry.RasterImage;
+			import com.degrafa.geometry.RasterText;
+			
+			import gssim.gssimstudio.editor.flare.query.BinaryExpression;
+			
+			import flashx.textLayout.formats.TextAlign;
+			
+			import gssim.gssimstudio.editor.gssim.components.CameleonLabel;
+			import gssim.gssimstudio.editor.gssim.multiDrag.MultiDragContainer;
+			import gssim.gssimstudio.editor.gssim.multiDrag.SelectionBox;
+			import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+			import gssim.gssimstudio.editor.gssim.topology.layouts.ILayout;
+			
+			import mx.collections.ArrayCollection;
+			import mx.controls.Text;
+			import mx.events.ResizeEvent;
+			
+			import gssim.gssimstudio.editor.script.event.InvalidActionEvent;
+			import gssim.gssimstudio.editor.script.event.LinkEvent;
+			import gssim.gssimstudio.editor.script.event.ObjectEvent;
+			
+			import spark.components.Group;
+			import spark.components.Label;
+			/**
+			 *  Dispatched when user clicked a link.
+			 *
+			 *  @eventType script.event.LinkMouseEvent
+			 */
+			[Event(name="LinkClick", type="script.event.LinkEvent")]
+			
+			/**
+			 *  Dispatched when user clicked a router.
+			 *
+			 *  @eventType script.event.ObjectMouseEvent
+			 */
+			[Event(name="RouterClick", type="script.event.ObjectEvent")]
+			
+			/**
+			 *  Dispatched when an object moves on canvas.
+			 *
+			 *  @eventType script.event.ObjectMouseEvent
+			 */
+			[Event(name="ObjectMoved", type="script.event.ObjectEvent")]
+			
+			/**
+			 *  Dispatched when an object is removed from canvas.
+			 *
+			 *  @eventType script.event.ObjectMouseEvent
+			 */
+			[Event(name="ObjectRemoved", type="script.event.ObjectEvent")]
+			
+			/**
+			 *  Dispatched when canvas is cleaned.
+			 *
+			 *  @eventType flash.events.Event
+			 */
+			[Event(name="Cleaned", type="flash.events.Event")]
+			
+			/**
+			 *  Dispatched when canvas is moved.
+			 *
+			 *  @eventType flash.events.Event
+			 */
+			[Event(name="CanvasMoved", type="flash.events.Event")]
+			
+			/**
+			 *  Flash simple error message with explanation of the problem
+			 *
+			 *  @eventType flash.events.Event
+			 */
+			[Event(name="InvalidAction", type="script.event.InvalidActionEvent")]
+			
+			public static const CLEANED:String = "Cleaned";
+			public static const LINK_CLICK:String = "LinkClick";
+			public static const ROUTER_CLICK:String = "RouterClick";
+			public static const OBJECT_MOVED:String = "ObjectMoved";
+			public static const OBJECT_REMOVED:String = "ObjectRemoved";
+			public static const CANVAS_MOVED:String = "CanvasMoved";
+			public static const INVALID_ACTION:String = "InvalidAction";
+			
+			public static const MESSAGE_cantConnectNodes : String = "Nie moÅŒna poÅÄ
+czyÄ obiektÃ³w.";
+			
+			public static const NORMAL_MODE:String = "NormalMode";
+			public static const LINK_MODE:String = "LinkMode";
+			public static const REMOVE_MODE:String = "RemoveMode";
+			public static const INFO_MODE:String = "InfoMode";
+		
+			import gssim.gssimstudio.editor.gssim.topology.RouterObject;
+			import com.degrafa.core.collections.GraphicsCollection;
+			import mx.binding.utils.BindingUtils;
+			import gssim.gssimstudio.editor.gssim.topology.Linker;
+			import gssim.gssimstudio.editor.gssim.topology.NetworkObjectLinker;
+			import com.degrafa.paint.SolidStroke;
+			import com.degrafa.GeometryGroup;
+			import com.degrafa.core.collections.GeometryCollection;
+			import com.degrafa.geometry.Line;
+			import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+			import gssim.gssimstudio.editor.gssim.topology.Graph;
+			import mx.controls.Alert;
+			import com.degrafa.geometry.RoundedRectangle;
+			
+			
+			private var _labelsArray : Object; //map id -> GeometryGroup with RasterText inside
+					
+			private var _draggingTarget : GenderObject;
+			private var _isDragging : Boolean;
+			private var _isScrolling : Boolean;
+			private var _isSelecting : Boolean;
+			private var _currentMode : String;
+			private var _linkingTarget : GenderObject;
+			private var _linkingLink : Linker;
+			private var _selectionBox : SelectionBox;
+			
+			public var maximumWidth : Number = 5000;
+			public var maximumHeight : Number = 5000;
+			
+			private static var _graph : Graph;
+			public static function get graph() : Graph
+			{
+				if (_graph == null) _graph = new Graph();
+				return _graph;
+			}
+			
+			private var _dragGroup : MultiDragContainer;
+		
+			/**
+			 * Initialize the container. Register event listeners and create array objects.
+			 */
+			private function init() : void
+			{
+				_currentMode = NORMAL_MODE;
+				
+				this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownEventHandler);
+				this.addEventListener(MouseEvent.MOUSE_UP, mouseUpEventHandler);
+				this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
+				this.addEventListener(MouseEvent.CLICK, mouseClickEventHandler);
+				
+				//link visible when joining
+				_linkingLink = new Linker(0,0,0,0);
+				surface.graphicsCollection.addItem(_linkingLink);
+				_linkingLink.target = surface;
+				surface.setChildIndex(_linkingLink, 0);
+				_linkingLink.visible = false;
+				
+				//selectionBox visible when shift-clicking
+				_selectionBox = new SelectionBox();
+				surface.addChild(_selectionBox);
+				surface.setChildIndex(_selectionBox, 0);
+				_selectionBox.visible = false;
+				
+				_dragGroup = new MultiDragContainer();
+				
+				_labelsArray = new Object();
+				
+				_graph = new Graph();
+			}
+		
+			/**
+			 * Fired when user moves object around the canvas. Updates the position of label and fires event OBJECT_MOVED.
+			 */
+			private function objectMovedEventHandler(event : ObjectEvent) : void
+			{
+				dispatchEvent(new ObjectEvent(OBJECT_MOVED, event.object));
+				var label : Group = _labelsArray[event.object.id] as Group;
+				label.x = event.object.x;
+				label.y = event.object.y - 12;
+			}
+			
+			/**
+			 * Validates position of the canvas - if it is in bounds of the visible area. Fires CANVAS_MOVED event.
+			 */
+			public function validatePosition() : void
+			{
+				var matrix : Matrix = surface.transform.matrix;
+				if (surface.x > 0) surface.x = 0;
+				if (surface.y > 0) surface.y = 0;
+				if (surface.x < -(maximumWidth*matrix.a)+this.width) surface.x = -(maximumWidth*matrix.a)+this.width;
+				if (surface.y < -(maximumHeight*matrix.d)+this.height) surface.y = -(maximumHeight*matrix.d)+this.height;
+				dispatchEvent(new Event(CANVAS_MOVED));
+			}
+		
+			/**
+			 * Fired when user dragged a selection box and released mouse button or SHIFT key.
+			 * Objects within selection box are added to the current group.
+			 */
+			private function stopSelection(addItems : Boolean) : void
+			{
+				if (addItems)
+				{
+					for each (var node : Object in _graph.nodes)
+					{
+						if (node is GenderObject)
+						{
+							var go : GenderObject = node as GenderObject;
+							if (_selectionBox.isInBounds(go.x + go.width/2, go.y + go.height/2))
+								_dragGroup.AddObject(go);
+						}
+					}
+				}
+				_selectionBox.stopSelection();
+			}
+		
+			/**
+			 * Handles mouse move actions. Checks if user is using selection box, is scrolling the canvas,
+			 * is dragging an object or is currently in lining mode. In each case appropriate actions are held.
+			 */
+			private function mouseMoveEventHandler(event : MouseEvent) : void
+			{
+				if (event.shiftKey)
+				{
+					_selectionBox.update(surface.contentMouseX, surface.contentMouseY);
+				}
+				else
+				{
+					_isSelecting = false;
+					stopSelection(event.shiftKey);
+				}
+				if (_isScrolling)
+				{
+					validatePosition();
+				}
+				if (_isDragging)
+				{
+					if (_draggingTarget != null)
+					{
+						_dragGroup.applyDrag(_draggingTarget);
+					}
+				}
+				if (_currentMode == LINK_MODE && _linkingTarget != null)
+				{
+					_linkingLink.x2 = surface.contentMouseX;
+					_linkingLink.y2 = surface.contentMouseY;
+					_linkingLink.refresh();
+				}
+			}
+		
+			/**
+			 * Handles mouse button down event. Checks if user clicked on the surface or on object and
+			 * helds appropriate actions.
+			 */
+			private function mouseDownEventHandler(event : MouseEvent) : void
+			{
+				if (event.target == this)
+				{
+					if (event.shiftKey) //draw multi-select rectangle
+					{
+						_selectionBox.startSelection(surface.contentMouseX, surface.contentMouseY);
+						_isSelecting = true;
+					}
+					else //move the surface
+					{
+						surface.startDrag();
+						_isScrolling = true;
+					}
+				}
+			}
+			
+			/**
+			 * Stops all drag actions on the surface and objects.
+			 */
+			public function forceStopDrag(event : Event) : void
+			{
+				surface.stopDrag();
+				_isScrolling = false;
+				if (_isDragging)
+				{
+					_draggingTarget.stopDrag();
+					_draggingTarget = null;
+					_isDragging = false;
+				}
+			}
+			
+			/**
+			 * Handles mouse button up event. Used to finish common tasks susch as selection, scrolling,
+			 * dragging and linking.
+			 */
+			private function mouseUpEventHandler(event : MouseEvent) : void
+			{
+				if (_isSelecting)
+				{
+					stopSelection(event.shiftKey);
+					_isSelecting = false;
+				}
+				if (_isScrolling)
+				{
+					surface.stopDrag();
+					_isScrolling = false;
+				}
+				if (_isDragging)
+				{
+					forceStopDrag(event);
+				}
+				
+				//always hide this additional link on MouseUp
+				if (_currentMode == LINK_MODE) {
+					_linkingLink.visible = false;
+					_linkingTarget = null;					
+				}
+			}
+			
+			private function mouseDownOnObjectEventHandler(event : MouseEvent) : void
+			{
+				if (_currentMode == NORMAL_MODE)
+				{
+					_isDragging = true;
+					_draggingTarget = event.target as GenderObject;
+					if (!event.shiftKey)
+						_dragGroup.empty();
+					_dragGroup.setStartPosition(_draggingTarget);
+					_dragGroup.AddObject(_draggingTarget);
+					_draggingTarget.startDrag();
+				}
+				else
+				if (_currentMode == LINK_MODE)
+				{
+					if (_linkingTarget == null)
+					{
+						_linkingTarget = event.target as GenderObject;
+						_linkingLink.x1 = _linkingTarget.x + _linkingTarget.width / 2;
+						_linkingLink.y1 = _linkingTarget.y + _linkingTarget.height / 2;
+						_linkingLink.x2 = _linkingLink.x1;
+						_linkingLink.y2 = _linkingLink.y1;
+						_linkingLink.refresh();
+						_linkingLink.visible = true;
+					}
+				}
+			}
+			
+			private function mouseUpOnLinkEventHandler(event : MouseEvent) : void
+			{
+				var _link : NetworkObjectLinker = event.target as NetworkObjectLinker;
+				if (_currentMode == REMOVE_MODE)
+				{
+					_graph.unlink(_link.NodeFrom, _link.NodeTo);
+					_link.NodeFrom.links.removeItemAt(_link.NodeFrom.links.getItemIndex(_link));
+					_link.NodeTo.links.removeItemAt(_link.NodeTo.links.getItemIndex(_link));
+					_link.graphics.clear();
+					surface.graphicsCollection.removeItem(_link);
+				}
+				else
+				if (_currentMode == LINK_MODE)
+				{
+					
+				}
+				else
+				if (_currentMode == INFO_MODE)
+				{
+					dispatchEvent(new LinkEvent(LINK_CLICK, _link));
+				}
+			}
+			
+			private function mouseUpOnObjectEventHandler(event : MouseEvent) : void
+			{
+				var targetObject : GenderObject = event.target as GenderObject;
+				if (_currentMode == LINK_MODE)
+				{
+					if (targetObject == null)
+					{
+						_linkingTarget = null
+					}
+					else if (targetObject != _linkingTarget)
+					{
+						linkObjects(_linkingTarget, targetObject);
+						_linkingTarget = null;
+					}
+				}
+				else
+				if (_currentMode == REMOVE_MODE)
+				{
+					targetObject.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownOnObjectEventHandler);
+					targetObject.removeEventListener(MouseEvent.MOUSE_UP, mouseUpOnObjectEventHandler);
+					targetObject.removeEventListener(GenderObject.OBJECT_MOVED, objectMovedEventHandler);
+					surface.removeChild(targetObject);
+					targetObject.clean();
+					_graph.remove(targetObject);
+					//remove label
+					surface.removeChild(_labelsArray[targetObject.id]);
+					_labelsArray[targetObject.id] = null;
+					dispatchEvent(new ObjectEvent(OBJECT_REMOVED, targetObject));
+				}
+				else
+				if (_currentMode == INFO_MODE)
+				{
+					dispatchEvent(new ObjectEvent(ROUTER_CLICK, targetObject));
+				}
+			}
+			
+			private function linkObjects(object1 : GenderObject, object2 : GenderObject) : NetworkObjectLinker
+			{
+				if (object1 == null || object2 == null) return null;
+				if (object1 != object2)
+				{
+					if (object1.canBeConnected(object2) && object2.canBeConnected(object1))
+					{
+						var link : NetworkObjectLinker = new NetworkObjectLinker(object1, object2);
+						link.addEventListener(MouseEvent.CLICK, mouseUpOnLinkEventHandler);
+						object1.links.addItem(link);
+						object2.links.addItem(link);
+						surface.graphicsCollection.addItem(link);
+						link.target = surface;
+						surface.setChildIndex(link, 0);
+						_graph.link(object1, object2);
+						return link;
+					}
+					else
+					{
+						dispatchEvent(new InvalidActionEvent(INVALID_ACTION, MESSAGE_cantConnectNodes));
+						return null;
+					}
+				}
+				return null;
+			}
+			
+			public function linkObjectsById(id1 : String, id2 : String, baudRate : Number = 0, propDelay : Number = 0, mtu : Number = 0) : void
+			{
+				var link :NetworkObjectLinker = linkObjects(_graph.find(id1) as GenderObject, _graph.find(id2) as GenderObject);
+				link.BaudRate = baudRate;
+				link.PropDelay = propDelay;
+				link.MTU = mtu;
+			}
+			
+			private function mouseClickEventHandler(event : MouseEvent) : void
+			{
+				dropDraggedObject();
+			}
+			
+			private function dropDraggedObject() : void
+			{
+				if (_isDragging)
+				{
+					_isDragging = false;
+					if (_draggingTarget != null)
+					{
+						_draggingTarget.stopDrag();
+						_draggingTarget = null;
+					}
+				}
+			}
+			
+			public function addGenderObject(object : GenderObject) : void
+			{
+				surface.addChild(object);
+				_graph.add(object);
+				object.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownOnObjectEventHandler);
+				object.addEventListener(MouseEvent.MOUSE_UP, mouseUpOnObjectEventHandler);
+				object.addEventListener(GenderObject.OBJECT_MOVED, objectMovedEventHandler);
+				_dragGroup.empty();
+				_dragGroup.setStartPosition(object);
+				_dragGroup.AddObject(object);
+				
+				var selected_label : CameleonLabel = new CameleonLabel();
+				BindingUtils.bindProperty(selected_label, "text", object, "nodeName");
+				BindingUtils.bindProperty(selected_label, "selectedColor", object, "selectedColor");
+				var gg : Group = new Group();
+				gg.addElement(selected_label);
+				surface.addChild(gg);
+				surface.setChildIndex(gg, surface.getChildIndex(object));
+
+				_labelsArray[object.id] = gg;
+				
+				_draggingTarget = object;
+				_isDragging = true;
+				
+				object.startDrag();
+			}
+			
+			public function resetLinkingMode() : void
+			{
+				if (_currentMode == LINK_MODE) _currentMode = NORMAL_MODE;
+				else _currentMode = LINK_MODE;
+				_linkingTarget = null;
+			}
+			
+			public function resetRemoveMode() : void
+			{
+				if (_currentMode == REMOVE_MODE) _currentMode = NORMAL_MODE;
+				else _currentMode = REMOVE_MODE;
+				_linkingTarget = null;
+			}
+			
+			public function resetInfoMode() : void
+			{
+				if (_currentMode == INFO_MODE) _currentMode = NORMAL_MODE;
+				else _currentMode = INFO_MODE;
+				_linkingTarget = null;
+			}
+			
+			public function empty() : void
+			{
+				_graph.empty();
+				while (surface.graphicsCollection.items.length) {
+					surface.graphicsCollection.removeItemAt(0);
+				}
+				while (surface.numChildren) {
+					surface.removeChildAt(0);
+				}
+				surface.graphicsCollection.addItem(_linkingLink);
+				_linkingLink.target = surface;
+				surface.setChildIndex(_linkingLink, 0);
+				surface.addChild(_selectionBox);
+				surface.setChildIndex(_selectionBox, 0);
+				_labelsArray = new Object();
+				dispatchEvent(new Event(CLEANED));
+				
+				//center screen
+				surface.x = -maximumWidth/2 + this.width/2;
+				surface.y = -maximumHeight/2 + this.height/2;
+				validatePosition();
+			}
+			
+			public function applyLayout(layout: ILayout) : void
+			{
+				layout.doLayout(_graph);
+				if (!layout.isStatic()) _graph.translate(-surface.x + this.width /4, -surface.y + this.height /4);
+			}
+			
+			public function applyZoom(value : Number, pos_x : Number, pos_y : Number) : void
+			{
+				var matrix : Matrix = surface.transform.matrix;
+				matrix.translate(-pos_x, -pos_y);
+				matrix.scale(value, value);
+				matrix.translate(pos_x, pos_y);
+				surface.transform.matrix = matrix;
+			}
+		]]>
+	</mx:Script>
+	<degrafa:Surface id="surface" width="100%" height="100%">
+	</degrafa:Surface>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/ResourceParamsWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/ResourceParamsWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/ResourceParamsWindow.mxml	(revision 15)
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<v:ObjectParamsWindow 
+	xmlns:v="gssim.gssimstudio.editor.gssim.editors.topology.*" 
+	xmlns:mx="http://www.adobe.com/2006/mxml" 
+	width="400" 
+	height="300"
+>
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.editors.topology.chartWindows.*;
+			
+			private function showTasksChart() : void
+			{	
+				var windowName : String = this.name + ".TasksGanttChart";
+				if (this.parent.getChildByName(windowName) == null)
+				{
+					var tasksChartWindow : TasksGanttChart = new TasksGanttChart();
+					tasksChartWindow.name = windowName;
+					windowManager.add(tasksChartWindow);
+				}
+			}
+			
+			private function showWaitingTimeChart() : void
+			{
+				
+			}
+			
+			private function showReservationsChart() : void
+			{
+				
+			}
+			
+			private function showResourcesChart() : void
+			{
+				var windowName : String = this.name + ".ResourcesChart";
+				if (this.parent.getChildByName(windowName) == null)
+				{
+					var resourcesChartWindow : ResourcesChart = new ResourcesChart();
+					resourcesChartWindow.name = windowName;
+					windowManager.add(resourcesChartWindow);
+				}
+			}
+			
+			private function showProcessorsChart() : void
+			{
+				
+			}
+			
+			private function showEnergyUsageChart() : void
+			{
+				
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox>
+		<mx:Button 
+			label="Tasks Gantt Chart"
+			click="showTasksChart()"
+		/>
+		<mx:Button 
+			label="Waiting Time Gantt Chart"
+			click="showWaitingTimeChart()"
+		/>
+		<mx:Button 
+			label="Reservations Gantt Chart"
+			click="showReservationsChart()"
+		/>
+		<mx:Button 
+			label="Resources Area Chart"
+			click="showResourcesChart()"
+		/>
+		<mx:Button 
+			label="Processors Gantt Chart"
+			click="showProcessorsChart()"
+		/>
+		<mx:Button 
+			label="Energy Usage Chart"
+			click="showEnergyUsageChart()"
+		/>
+	</mx:VBox>
+</v:ObjectParamsWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/UserParamsWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/UserParamsWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/UserParamsWindow.mxml	(revision 15)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<v:ObjectParamsWindow 
+	xmlns:v="gssim.gssimstudio.editor.gssim.editors.topology.*" 
+	xmlns:mx="http://www.adobe.com/2006/mxml" 
+	width="400" 
+	height="300"
+>
+	
+</v:ObjectParamsWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/RouterParamsWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/RouterParamsWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/paramsWindows/RouterParamsWindow.mxml	(revision 15)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<v:ObjectParamsWindow
+	xmlns:mx="http://www.adobe.com/2006/mxml" 
+	xmlns:v="gssim.gssimstudio.editor.gssim.editors.topology.*"
+	width="400" 
+	height="300"
+>
+
+</v:ObjectParamsWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/NetworkEditorToolbox.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/NetworkEditorToolbox.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/NetworkEditorToolbox.mxml	(revision 15)
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Contains basic tools available in Network Editor.
+-->
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" 
+					 xmlns:fx="http://ns.adobe.com/mxml/2009"  
+					 xmlns:s="library://ns.adobe.com/flex/spark"
+					 xmlns:mx="library://ns.adobe.com/flex/mx"
+					 width="232" height="155" title="{resourceManager.getString('TopologyEditor', 'Toolbox')}"
+					 creationComplete="setOptionPane();"
+					 originalX="{parentApplication.width - width}" originalY="0" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+<fx:Script>
+	<![CDATA[
+		import flashx.textLayout.tlf_internal;
+		
+		import gssim.gssimstudio.editor.gssim.skins.IconButtonSkin;
+		import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+		import gssim.gssimstudio.editor.gssim.topology.GenderObjectFactory;
+		import gssim.gssimstudio.editor.gssim.topology.layouts.ILayout;
+		import gssim.gssimstudio.editor.gssim.topology.layouts.gssimFileLayout;
+		import gssim.gssimstudio.editor.gssim.topology.layouts.gssimForceDirectedLayout;
+		import gssim.gssimstudio.editor.gssim.topology.layouts.gssimIndentLayout;
+		import gssim.gssimstudio.editor.gssim.topology.layouts.gssimRadialLayout;
+		import gssim.gssimstudio.editor.gssim.topology.layouts.gssimSimpleLayout;
+		
+		import mx.core.Application;
+		import mx.core.FlexGlobals;
+	
+		public var canvas : ObjectCanvas;
+		
+		[Bindable]
+		private var isLinking : Boolean = false;
+		
+		[Bindable]
+		private var isRemoving : Boolean = false;
+		
+		[Bindable]
+		private var isInfo : Boolean = false;
+	
+		private function addRouterClick(event:MouseEvent):void
+		{
+			if (canvas != null)
+			{
+				canvas.addGenderObject(
+					GenderObjectFactory.createRouter(
+						canvas.surface.contentMouseX - 47,
+						canvas.surface.contentMouseY - 47,
+						94,
+						94)
+					);
+			}
+		}
+		
+		private function addResourceClick(event:MouseEvent):void
+		{
+			if (canvas != null)
+			{
+				canvas.addGenderObject(
+					GenderObjectFactory.createResource(
+						canvas.surface.contentMouseX - 47,
+						canvas.surface.contentMouseY - 47,
+						94,
+						94)
+					);
+			}
+		}
+		
+		private function addUserClick(event:MouseEvent):void
+		{
+			if (canvas != null)
+			{
+				canvas.addGenderObject(
+					GenderObjectFactory.createUser(
+						canvas.surface.contentMouseX - 47,
+						canvas.surface.contentMouseY - 47,
+						94,
+						94)
+					);
+			}
+		}
+		
+		private function addClusterClick(event:MouseEvent):void
+		{
+			if (canvas != null)
+			{
+				canvas.addGenderObject(
+					GenderObjectFactory.createCluster(
+						canvas.surface.contentMouseX - 47,
+						canvas.surface.contentMouseY - 47,
+						94,
+						94)
+				);
+			}
+		}
+		
+		private function setOptionPane():void
+		{
+			secondPane.selectedChild=activateDragMode.selected ? addPane : (activateInfoMode.selected ? layoutPane : empty);
+			if (secondPane.selectedChild == addPane)
+			{
+				this.height=141;	
+			}
+			else if (secondPane.selectedChild == layoutPane)
+			{
+				this.height=155;	
+			}
+			else this.height=85;
+		}
+		
+		private function activateDragModeClick(event:MouseEvent):void
+		{
+			if (isLinking) canvas.resetLinkingMode();
+			if (isRemoving) canvas.resetRemoveMode();
+			if (isInfo) canvas.resetInfoMode(); 
+			isLinking = false;
+			isRemoving = false;
+			isInfo = false;
+			activateDragMode.selected = true;
+			setOptionPane();
+		}
+		
+		private function activateLinkAddClick(event:MouseEvent):void
+		{
+			canvas.resetLinkingMode();
+			isLinking = !isLinking;
+			isRemoving = false;
+			isInfo = false;
+			setOptionPane();
+		}
+		
+		private function activateLinkRemoveClick(event:MouseEvent):void
+		{
+			canvas.resetRemoveMode();
+			isLinking = false;
+			isInfo = false;
+			isRemoving = !isRemoving;
+			setOptionPane();
+		}
+		
+		private function activateInfoClick(event:MouseEvent):void
+		{
+			canvas.resetInfoMode();
+			isLinking = false;
+			isRemoving = false;
+			isInfo = !isInfo;
+			setOptionPane();
+		}
+		
+		private function simpleLayoutClick(event:MouseEvent):void
+		{
+			var layout : ILayout = new gssimSimpleLayout();
+			canvas.applyLayout(layout);
+		}
+		
+		private function forceDirectedLayoutClick(event:MouseEvent):void
+		{
+			var layout : ILayout = new gssimForceDirectedLayout();
+			canvas.applyLayout(layout);
+		}
+		
+		private function radialLayoutClick(event:MouseEvent):void
+		{
+			var layout : ILayout = new gssimRadialLayout();
+			canvas.applyLayout(layout);
+		}
+		
+		private function indentLayoutClick(event:MouseEvent):void
+		{
+			var layout : ILayout = new gssimIndentLayout();
+			canvas.applyLayout(layout);
+		}
+		
+		private function fileLayoutClick(event:MouseEvent):void
+		{
+			var layout : ILayout = new gssimFileLayout(parentApplication.width);
+			canvas.applyLayout(layout);
+		}
+	]]>
+</fx:Script>
+<s:Group>
+	<s:VGroup x="5" y="5">
+		<mx:HBox>
+			<components:IconToggleButton id="activateDragMode" click="activateDragModeClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin"
+				height="48" width="48" selected="{!(isLinking || isRemoving || isInfo)}" toolTip="{resourceManager.getString('TopologyEditor', 'NormalMode')}"
+				iconUp="assets/dragButton.png" iconSelectedUp="assets/dragButtonDown.png"/>
+			<components:IconToggleButton id="activateInfoMode" click="activateInfoClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin"
+				height="48" width="48" selected="{isInfo}" toolTip="{resourceManager.getString('TopologyEditor', 'PropertiesMode')}"
+				iconUp="assets/infoButton.png" iconSelectedUp="assets/infoButtonDown.png"/>
+			<components:IconToggleButton id="activateLinkMode" click="activateLinkAddClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin"
+				height="48" width="48" selected="{isLinking}" toolTip="{resourceManager.getString('TopologyEditor', 'LinkMode')}"
+				iconUp="assets/linkButton.png" iconSelectedUp="assets/linkButtonDown.png"/>
+			<components:IconToggleButton id="activateRemoveMode" click="activateLinkRemoveClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin"
+				height="48" width="48" selected="{isRemoving}" toolTip="{resourceManager.getString('TopologyEditor', 'RemoveMode')}"
+				iconUp="assets/deleteButton.png" iconSelectedUp="assets/deleteButtonDown.png"/>
+		</mx:HBox>
+		<mx:ViewStack id="secondPane" width="216" height="{secondPane.selectedChild == layoutPane ? 64 : 48}" includeInLayout="{secondPane.selectedChild != empty}">
+			<mx:HBox id="addPane" showEffect="Fade">
+				<components:IconButton id="addRouter" mouseDown="addRouterClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+					height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'AddNew')} {resourceManager.getString('TopologyEditor', 'Router')}"
+					iconUp="assets/routerButton.png"/>
+				<components:IconButton id="addResource" mouseDown="addResourceClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+					height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'AddNew')} {resourceManager.getString('TopologyEditor', 'Resource')}"
+					iconUp="assets/resourceButton.png"/>
+				<components:IconButton id="addCluster" mouseDown="addClusterClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+					height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'AddNew')} {resourceManager.getString('TopologyEditor', 'Cluster')}"
+					iconUp="assets/clusterButton.png"/>
+				<components:IconButton id="addUser" mouseDown="addUserClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+				    height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'AddNew')} {resourceManager.getString('TopologyEditor', 'User')}"
+				    iconUp="assets/userButton.png"/>
+			</mx:HBox>
+			<mx:HBox id="layoutPane" showEffect="Fade">
+				<components:IconButton id="fileLayout" click="fileLayoutClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+									   height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'File')}"
+									   iconUp="assets/layoutFile.png"/>
+				<components:IconButton id="simpleLayout" click="simpleLayoutClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+					height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'Simple')} {resourceManager.getString('TopologyEditor', 'Layout')}"
+					iconUp="assets/layoutDFS.png"/>
+				<components:IconButton id="forceDirectedLayout" click="forceDirectedLayoutClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+					height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'ForceDirected')} {resourceManager.getString('TopologyEditor', 'Layout')}"
+					iconUp="assets/layoutForce.png"/>
+				<components:IconButton id="radialLayout" click="radialLayoutClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+					height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'Radial')} {resourceManager.getString('TopologyEditor', 'Layout')}"
+					iconUp="assets/layoutRadial.png"/>
+				<components:IconButton id="indentLayout" click="indentLayoutClick(event);" skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+					height="48" width="48" toolTip="{resourceManager.getString('TopologyEditor', 'TreeIndent')} {resourceManager.getString('TopologyEditor', 'Layout')}"
+					iconUp="assets/layoutIndent.png"/>
+			</mx:HBox>
+			<mx:HBox id="empty">
+				
+			</mx:HBox>
+		</mx:ViewStack>
+	</s:VGroup>
+</s:Group>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectParamsWindow.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectParamsWindow.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectParamsWindow.as	(revision 15)
@@ -0,0 +1,15 @@
+package gssim.gssimstudio.editor.gssim.editors.topology
+{
+	import flexlib.mdi.containers.MDIWindow;
+	
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	
+	public class ObjectParamsWindow extends MDIWindow
+	{
+			public function init(object : GenderObject) : void
+			{
+				title = object.nodeName;
+				name = title;
+			}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/MainMenu.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/MainMenu.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/MainMenu.mxml	(revision 15)
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!---
+	Main menu of the Topology Editor.
+-->
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+<mx:Style source="gssim/gssimstudio/editor/assets/css/mainMenu.css"/>
+<mx:Script>
+	<![CDATA[
+		import flexlib.mdi.containers.MDICanvas;
+		
+		import gssim.gssimstudio.editor.gssim.components.TextInputWindow;
+		import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+		import gssim.gssimstudio.editor.gssim.experiment.ExperimentProperties;
+		import gssim.gssimstudio.editor.gssim.resources.file.resourceReader;
+		import gssim.gssimstudio.editor.gssim.resources.file.resourcesWriter;
+		import gssim.gssimstudio.editor.gssim.topology.file.topologyReader;
+		import gssim.gssimstudio.editor.gssim.topology.file.topologyWriter;
+		import gssim.gssimstudio.editor.script.command.OpenGeneralChartsWindowCommand;
+		import gssim.gssimstudio.editor.script.command.OpenMinimapWindowCommand;
+		import gssim.gssimstudio.editor.script.command.OpenToolboxWindowCommand;
+		import gssim.gssimstudio.editor.script.command.SaveToPNGCommand;
+		import gssim.gssimstudio.editor.script.event.TextMessageEvent;
+		import gssim.gssimstudio.editor.views.ExperimentEditor;
+		import gssim.gssimstudio.editor.views.TopologyEditor;
+		
+		import mx.controls.Alert;
+		import mx.core.IFlexDisplayObject;
+		import mx.events.CloseEvent;
+		import mx.graphics.codec.PNGEncoder;
+		import mx.managers.PopUpManager;
+	
+		//FIXME: there should be some better way to do this...
+		public var objectCanvas : ObjectCanvas;
+		public var mdiCanvas : MDICanvas;
+	
+		private function newFile() : void
+		{
+			objectCanvas.empty();
+		}
+	
+		private function openFile(): void
+		{
+			var _topologyReader : topologyReader = new topologyReader(objectCanvas);
+		}
+		
+		private function openResourceFile(): void
+		{
+			var _resourceReader : resourceReader = new resourceReader(objectCanvas);
+		}
+		
+		private function saveTopologyToFile(): void
+		{
+			if (ObjectCanvas.graph.isStronglyConnected())
+			{
+				var _topologyWriter : topologyWriter = new topologyWriter();
+			}
+			else
+			{
+				Alert.show("Graph is not fully connected. Please ensure that all objects are linked.");
+			}
+		}
+		
+		private function saveTopologyToServer(): void
+		{
+			if (ObjectCanvas.graph.isStronglyConnected())
+			{
+				var popup : IFlexDisplayObject = PopUpManager.createPopUp(parentApplication.viewStack, TextInputWindow , true);
+				var filenamePrompt:TextInputWindow=TextInputWindow(popup);
+				PopUpManager.centerPopUp(filenamePrompt);
+				filenamePrompt.init(resourceManager.getString('TopologyEditor', 'filenamePromptTitle'), resourceManager.getString('TopologyEditor', 'filenamePromptText'));
+				popup.addEventListener(CloseEvent.CLOSE, saveTopologyToServerEventHandler);
+			}
+			else
+			{
+				Alert.show("Graph is not fully connected. Please ensure that all objects are linked.");
+			}
+		}
+		
+		private function saveTopologyToServerEventHandler(event : TextMessageEvent) : void
+		{
+			event.currentTarget.removeEventListener(CloseEvent.CLOSE, saveTopologyToServerEventHandler);
+			parentApplication.service.uploadNetworkTopologyFile(event.text, ObjectCanvas.graph.toString());
+		}
+		
+		private function saveResourceToFile(): void
+		{
+			var _resourceWriter : resourcesWriter = new resourcesWriter();
+			_resourceWriter.saveToFile();
+		}
+
+		private function saveResourceToServer(): void
+		{
+			var _resourceWriter : resourcesWriter = new resourcesWriter();
+			var popup : IFlexDisplayObject = PopUpManager.createPopUp(parentApplication.viewStack, TextInputWindow , true);
+			var filenamePrompt:TextInputWindow=TextInputWindow(popup);
+			PopUpManager.centerPopUp(filenamePrompt);
+			filenamePrompt.init(resourceManager.getString('TopologyEditor', 'filenamePromptTitle'), resourceManager.getString('TopologyEditor', 'filenamePromptText'));
+			popup.addEventListener(CloseEvent.CLOSE, saveResourceToServerEventHandler);
+			tmpString = _resourceWriter.getXMLString();
+		}
+		
+		//fixme: laziness in code - it shouldn't be global for this class
+		private var tmpString : String;
+		
+		private function saveResourceToServerEventHandler(event : TextMessageEvent) : void
+		{
+			event.currentTarget.removeEventListener(CloseEvent.CLOSE, saveResourceToServerEventHandler);
+			parentApplication.service.uploadResourceFile(event.text, tmpString);
+		}
+		
+		private function openToolbox(): void
+		{
+			var k : OpenToolboxWindowCommand = new OpenToolboxWindowCommand(mdiCanvas);
+			k.execute();
+		}
+		
+		private function openMinimap(): void
+		{
+			var k : OpenMinimapWindowCommand = new OpenMinimapWindowCommand(mdiCanvas);
+			k.execute();
+		}
+		
+		private function saveAsPNG() : void
+		{
+			var canvas : ObjectCanvas = parentApplication.topologyEditor.objectCanvas;
+			var k : SaveToPNGCommand = new SaveToPNGCommand(canvas);
+			k.execute();
+		}
+				 
+	]]>
+</mx:Script>
+	<mx:HBox horizontalGap="0">
+	<components:RollOutMenu width="100%" height="100%">
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="showIconsButton" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'MenuTooltip')}"
+			label="{resourceManager.getString('TopologyEditor', 'Menu')}"
+			iconUp="assets/icon/ShowIcons.png"/>
+		<components:RollOutMenu menuIcon="assets/icon/NewFile.png" width="100%" height="100%" menuLabel="{resourceManager.getString('TopologyEditor', 'NetworkSubmenu')}">
+			<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="newFileButton" click="newFile()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'NewTooltip')}"
+				 label="{resourceManager.getString('TopologyEditor', 'New')}"
+				 iconUp="assets/icon/NewFile.png"/>
+			<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="openFileButton" click="openFile()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'OpenTooltip')}"
+				label="{resourceManager.getString('TopologyEditor', 'Open')}"
+				iconUp="assets/icon/OpenFile.png"/>
+			<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="saveFileButton" click="saveTopologyToFile()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'SaveTooltip')}"
+				label="{resourceManager.getString('TopologyEditor', 'Save')}"
+				iconUp="assets/icon/SaveFile.png"/>
+			<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="saveServerFileButton" click="saveTopologyToServer()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'SaveServerTooltip')}"
+										 label="{resourceManager.getString('TopologyEditor', 'SaveServer')}"
+										 iconUp="assets/icon/SaveFile.png"/>
+		</components:RollOutMenu>
+		<components:RollOutMenu menuIcon="assets/icon/NewFile.png" width="100%" height="100%" menuLabel="{resourceManager.getString('TopologyEditor', 'ResourcesSubmenu')}">
+			<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="openResourceFileButton" click="openResourceFile()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'OpenTooltip')}"
+										 label="{resourceManager.getString('TopologyEditor', 'Open')}"
+										 iconUp="assets/icon/OpenFile.png"/>
+			<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="saveResourceFileButton" click="saveResourceToFile()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'SaveTooltip')}"
+										 label="{resourceManager.getString('TopologyEditor', 'Save')}"
+										 iconUp="assets/icon/SaveFile.png"/>
+			<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="saveServerResourceFileButton" click="saveResourceToServer()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'SaveServerTooltip')}"
+										 label="{resourceManager.getString('TopologyEditor', 'SaveServer')}"
+										 iconUp="assets/icon/SaveFile.png"/>
+		</components:RollOutMenu>
+			
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="toolboxButton" click="openToolbox()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'Toolbox')}"
+			label="{resourceManager.getString('TopologyEditor', 'Tools')}"
+			iconUp="assets/icon/OpenToolbox.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="minimapButton" click="openMinimap()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'Minimap')}"
+			label="{resourceManager.getString('TopologyEditor', 'Map')}"
+			iconUp="assets/icon/OpenMinimap.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" id="saveAsPNGButton" click="saveAsPNG()" height="64" width="128" toolTip="{resourceManager.getString('TopologyEditor', 'PNGFileTooltip')}"
+									 label="{resourceManager.getString('TopologyEditor', 'PNGFile')}"
+									 iconUp="assets/icon/PNGFile.png"/>
+	</components:RollOutMenu>
+	</mx:HBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/GeneralChartsWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/GeneralChartsWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/GeneralChartsWindow.mxml	(revision 15)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="210" height="230"
+	maxWidth="220" maxHeight="240" title="{resourceManager.getString('TopologyEditor', 'Diagrams')}" >
+<mx:Style source="/gssim/gssimstudio/editor/assets/css/experimentWindow.css"/>
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.gssim.experiment.FileProxy;
+		import mx.controls.Alert;
+		
+	]]>
+</mx:Script>
+
+	<mx:VBox>
+		<mx:TabNavigator width="203" height="200" paddingLeft="5">
+			<mx:VBox label="{resourceManager.getString('TopologyEditor', 'Diagrams')}">
+				<mx:Button label="{resourceManager.getString('TopologyEditor', 'Processors')}" id="createDiagrams_processors" width="180" toolTip="Processors gantt chart"/>
+				<mx:Button label="{resourceManager.getString('TopologyEditor', 'Resources')}" id="createDiagrams_resources" width="180" toolTip="Resources gantt chart"/>
+				<mx:Button label="{resourceManager.getString('TopologyEditor', 'Tasks')}" id="createDiagrams_tasks" width="180" toolTip="Tasks gantt diagram"/>
+				<mx:Button label="{resourceManager.getString('TopologyEditor', 'TasksWaitingTime')}" id="createDiagrams_tasksWaitingTime" width="180" toolTip="Rasks waiting time gantt diagram"/>
+				<mx:Button label="{resourceManager.getString('TopologyEditor', 'Reservations')}" id="createDiagrams_reservations" width="180" toolTip="Reservations of tasks gantt diagram"/>
+				<mx:Button label="{resourceManager.getString('TopologyEditor', 'EnergyUsage')}" id="createDiagrams_energyUsage" width="180" toolTip="Energy usage diagram"/>
+			</mx:VBox>
+		</mx:TabNavigator>
+	</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectPropertiesWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectPropertiesWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/topology/ObjectPropertiesWindow.mxml	(revision 15)
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindow xmlns="flexlib.mdi.containers.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="360" height="80"
+		   xmlns:s="library://ns.adobe.com/flex/spark" close="closeHandler(event)"
+	creationComplete="fillFields();" maxWidth="370" maxHeight="90" resizable="false" xmlns:states="com.degrafa.states.*">
+<mx:Script>
+	<![CDATA[
+		import flexlib.mdi.events.MDIWindowEvent;
+		
+		import gssim.gssimstudio.editor.gssim.editors.resources.ComputingResourceWindow;
+		import gssim.gssimstudio.editor.gssim.editors.resources.QueueResourceWindow;
+		import gssim.gssimstudio.editor.gssim.resources.ComputingResource;
+		import gssim.gssimstudio.editor.gssim.resources.QueueResource;
+		import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+		import gssim.gssimstudio.editor.gssim.topology.ResourceObject;
+		
+		import mx.binding.utils.BindingUtils;
+		import mx.controls.Alert;
+		
+		protected var _object : GenderObject;
+		
+		public function init(object : GenderObject) : void
+		{
+			_object = object;
+			title = _object.nodeName;
+			name = title;
+			if (object is ResourceObject)
+			{
+				if ((object as ResourceObject).cluster)
+					currentState = "cluster";
+				else
+					currentState = "resource";
+			}
+			else currentState = "object";
+		}
+		
+		protected function fillFields() : void
+		{
+			if (_object == null) return;
+			NameInput.text = _object.nodeName;
+		}
+		
+		private function addResource() : void
+		{
+			(_object as ResourceObject).clusteredResources.addItem(new ComputingResource());
+		}
+		
+		public function removeResource() : void
+		{
+			(_object as ResourceObject).clusteredResources.removeItemAt(dg.selectedIndex);
+		}
+		
+		public function editResource() : void
+		{
+			var winPar : ComputingResourceWindow = new ComputingResourceWindow();
+			windowManager.add(winPar);
+			winPar.setParams(dg.selectedItem as ComputingResource);
+		}
+		
+		public function editQueue() : void
+		{
+			var winPar : QueueResourceWindow = new QueueResourceWindow();
+			windowManager.add(winPar);
+			if ((_object as ResourceObject).queue == null) (_object as ResourceObject).queue = new QueueResource();
+			(_object as ResourceObject).queue.resourceId = NameInput.text + "_queue";
+			winPar.setParams((_object as ResourceObject).queue);
+		}
+		
+		public function editFrontend() : void
+		{
+			var winPar : ComputingResourceWindow = new ComputingResourceWindow();
+			windowManager.add(winPar);
+			if ((_object as ResourceObject).frontend == null)
+			{
+				(_object as ResourceObject).frontend = new ComputingResource();
+			}
+			(_object as ResourceObject).frontend.resourceId = NameInput.text;
+			winPar.setParams((_object as ResourceObject).frontend, true);
+		}
+
+		protected function closeHandler(event:MDIWindowEvent):void
+		{
+			if (_object is ResourceObject)
+			{
+				if ((_object as ResourceObject).frontend != null)
+				{
+					(_object as ResourceObject).frontend.resourceId = _object.nodeName;
+				}
+				if ((_object as ResourceObject).queue != null)
+				{
+					(_object as ResourceObject).queue.resourceId = _object.nodeName + "_queue";
+				}
+			}
+			_object.UpdateLinkNames();
+		}
+
+	]]>
+</mx:Script>
+
+<states>
+	<s:State name="cluster">
+		<mx:SetProperty target="clusterEdit" name="visible" value="true"/>
+		<mx:SetProperty target="clusterEdit" name="includeInLayout" value="true"/>
+		<mx:SetProperty target="EditResourceButton" name="visible" value="true"/>
+		<mx:SetProperty target="EditResourceButton" name="includeInLayout" value="true"/>
+		<mx:SetProperty target="{this}" name="height" value="350"/>
+		<mx:SetProperty target="{this}" name="maxHeight" value="360"/>
+	</s:State>
+	<s:State name="resource">
+		<mx:SetProperty target="EditResourceButton" name="visible" value="true"/>
+		<mx:SetProperty target="EditResourceButton" name="includeInLayout" value="true"/>
+		<mx:SetProperty target="clusterEdit" name="visible" value="false"/>
+		<mx:SetProperty target="clusterEdit" name="includeInLayout" value="false"/>
+		<mx:SetProperty target="{this}" name="height" value="130"/>
+		<mx:SetProperty target="{this}" name="maxHeight" value="140"/>
+	</s:State>
+	<s:State name="object">
+		<mx:SetProperty target="EditResourceButton" name="visible" value="false"/>
+		<mx:SetProperty target="EditResourceButton" name="includeInLayout" value="false"/>
+		<mx:SetProperty target="clusterEdit" name="visible" value="false"/>
+		<mx:SetProperty target="clusterEdit" name="includeInLayout" value="false"/>
+		<mx:SetProperty target="{this}" name="height" value="100"/>
+		<mx:SetProperty target="{this}" name="maxHeight" value="110"/>
+	</s:State>
+</states>
+	
+	<mx:VBox width="100%">
+		<mx:HBox>
+			<mx:Label text="{resourceManager.getString('TopologyEditor', 'Name')}" width="140"/>
+			<mx:TextInput id="NameInput" width="150" restrict="a-zA-Z0-9" change="_object.nodeName = NameInput.text"/>
+		</mx:HBox>
+		<mx:VBox visible="false" includeInLayout="false" id="clusterEdit" width="100%">
+			<mx:DataGrid width="100%" id="dg" dataProvider="{(currentState == 'cluster' ? (_object as ResourceObject).clusteredResources : null)}">
+				<mx:columns>
+					<mx:DataGridColumn dataField="resourceId" headerText="{resourceManager.getString('WorkloadEditor', 'Name')}"/>
+					<mx:DataGridColumn dataField="count" headerText="{resourceManager.getString('TopologyEditor', 'Count')}"/>
+					<mx:DataGridColumn headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}" minWidth="160">
+						<mx:itemRenderer>
+							<mx:Component>
+								<mx:HBox paddingLeft="4">
+									<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="outerDocument.editResource()" height="30"/>
+									<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Remove')}" click="outerDocument.removeResource()" height="30"/>
+								</mx:HBox>
+							</mx:Component>
+						</mx:itemRenderer>
+					</mx:DataGridColumn>
+				</mx:columns>
+			</mx:DataGrid>
+			<mx:Button id="AddNewResourceButton" label="{resourceManager.getString('ResourceEditor', 'AddNewResource')}" click="addResource()" />
+			<mx:Button id="EditQueueButton" label="{resourceManager.getString('ResourceEditor', 'EditQueue')}" click="editQueue()" />
+		</mx:VBox>
+		<mx:Button id="EditResourceButton" label="{resourceManager.getString('ResourceEditor', 'EditResource')}" click="editFrontend()" />
+		<mx:Button label="{resourceManager.getString('TopologyEditor', 'Close')}" click="close();"/>
+	</mx:VBox>
+</MDIWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/TreeViewWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/TreeViewWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/TreeViewWindow.mxml	(revision 15)
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindowNoMaximize xmlns="gssim.gssimstudio.editor.gssim.flexmdi.*" xmlns:mx="http://www.adobe.com/2006/mxml" title="{resourceManager.getString('WorkloadEditor', 'TreeView')}" width="500" height="90%">
+<mx:Script>
+	<![CDATA[
+		import mx.events.ListEvent;
+		import mx.collections.ArrayCollection;
+		import gssim.gssimstudio.editor.views.WorkloadEditor;
+		
+		private function treeItemClick(event : ListEvent) : void
+		{
+			dg.dataProvider = new ArrayCollection();
+			for each (var attribute : XML in XML(tree.selectedItem).@*)
+			{
+				if (attribute.name() == "label") continue;
+				dg.dataProvider.addItem({name : attribute.name(), value : attribute.toXMLString()});
+			}
+		}
+		
+	]]>
+</mx:Script>
+<mx:VBox width="100%" height="100%">
+	<mx:Tree dataProvider="{WorkloadEditor.workload.getXML(true)}" height="100%" width="100%" labelField="@label" id="tree" change="treeItemClick(event)"/>
+
+	<mx:DataGrid id="dg" width="100%" height="100" >
+			<mx:columns>
+				<mx:DataGridColumn dataField="name" headerText="{resourceManager.getString('WorkloadEditor', 'Name')}"/>
+				<mx:DataGridColumn dataField="value" headerText="{resourceManager.getString('WorkloadEditor', 'Value')}"/>
+			</mx:columns>
+		</mx:DataGrid>
+</mx:VBox>
+</MDIWindowNoMaximize>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/FileManager.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/FileManager.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/FileManager.mxml	(revision 15)
@@ -0,0 +1,239 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:code="http://code.google.com/p/flexlib/" height="100%" xmlns:experiment="gssim.gssimstudio.editor.gssim.editors.experiment.*"
+		   label="{resourceManager.getString('ExperimentEditor', 'FileManager')}">
+
+<mx:Metadata>
+[ResourceBundle("ExperimentEditor")]
+</mx:Metadata>
+
+	<mx:Script>
+		<![CDATA[
+			import flash.events.Event;
+			import flash.net.FileReferenceList;
+			
+			import gssim.gssimstudio.editor.gssim.editors.experiment.WorkloadFastViewWindow;
+			import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+			import gssim.gssimstudio.editor.gssim.experiment.ExperimentProperties;
+			import gssim.gssimstudio.editor.gssim.experiment.FileProxy;
+			import gssim.gssimstudio.editor.gssim.resources.file.resourceReader;
+			import gssim.gssimstudio.editor.gssim.topology.file.topologyReader;
+			import gssim.gssimstudio.editor.gssim.workload.swf.WorkloadSWF;
+			import gssim.gssimstudio.editor.script.utils.ConjunctionArray;
+			import gssim.gssimstudio.editor.script.views.ViewsHelper;
+			import gssim.gssimstudio.editor.views.TopologyEditor;
+			
+			import mx.collections.ArrayCollection;
+			import mx.controls.Alert;
+			import mx.core.IUIComponent;
+			import mx.events.CloseEvent;
+			import mx.events.DragEvent;
+			import mx.managers.DragManager;
+			
+			import org.vinetoolkit.vine.net.events.VineUploadEvent;
+			
+			public static var selectedWorkloadFiles : ArrayCollection = new ArrayCollection();
+			public static var selectedTopologyFiles : ArrayCollection = new ArrayCollection();
+			public static var selectedResourceFiles : ArrayCollection = new ArrayCollection();
+			
+			[Bindable]
+			public var showDebug : Boolean = false;
+			
+			public function addNewWorkloadFile() : void
+			{
+				sendFile(updateWorkloadFile);
+			}
+			
+			private function updateWorkloadFile(event : VineUploadEvent) : void
+			{
+				parentApplication.service.allWorkloadFilesUploaded();
+				finishUploading();
+			}
+			
+			public function addNewTopologyFile() : void
+			{
+				sendFile(updateTopologiesFile);
+			}
+			
+			private function updateTopologiesFile(event : VineUploadEvent) : void
+			{
+				parentApplication.service.allTopologiesFilesUploaded();
+				finishUploading();
+			}
+			
+			public function addNewResourceFile() : void
+			{
+				sendFile(updateResourceFile);
+			}
+			
+			private function updateResourceFile(event : VineUploadEvent) : void
+			{
+				parentApplication.service.allResourcesFilesUploaded();
+				finishUploading();
+			}
+			
+			public function removeItem(datagrid : DataGrid) : Object
+			{
+				var obj : Object = datagrid.selectedItem;
+				(datagrid.dataProvider as ArrayCollection).removeItemAt(datagrid.selectedIndex);
+				return obj;
+			}
+			
+			public function addItemToWorkspace(source : DataGrid, target : ArrayCollection) : Object
+			{
+				var obj : Object = source.selectedItem;
+				if (!target.contains(obj))
+					target.addItem(obj);
+				return obj;
+			}
+			
+			public function removeFileItem(datagrid : DataGrid) : void
+			{
+				var obj : Object = datagrid.selectedItem;
+				parentApplication.service.deleteFileItem(obj.fileUrl,obj.folderUrl);
+			}  
+			
+			public function viewWorkload() : void
+			{
+				var file : FileProxy = workloadFilesDG.selectedItem as FileProxy;
+				if (!file.valid) return;
+				var workloadView : WorkloadFastViewWindow = new WorkloadFastViewWindow();
+				mdiCanvas.windowManager.add(workloadView);
+				workloadView.setWorkload(new WorkloadSWF(file.data));
+			}
+			
+			public function loadTopology() : void
+			{
+				var file : FileProxy = topologyFilesDG.selectedItem as FileProxy;
+				if (!file.valid) return;
+				var reader : topologyReader = new topologyReader(parentApplication.topologyEditor.objectCanvas, false);
+				reader.readFromBinary(file.data);
+			}
+			
+			public function loadResources() : void
+			{
+				var file : FileProxy = resourceFilesDG.selectedItem as FileProxy;
+				if (!file.valid) return;
+				var reader : resourceReader = new resourceReader(parentApplication.topologyEditor.objectCanvas, false);
+				reader.readFromString(file.data);
+			}
+			
+			/*************************
+			 * File Transfer Methods *
+			 *************************/			
+			private function sendFile(uploadResult : Object) : void
+			{
+				if (parentApplication.isFileTransfering) return;
+				parentApplication.isFileTransfering = true;
+				parentApplication.upload(true, true, null, uploadResult, uploadFault, null, uploadCancel);//uploadSelect, uploadStart);
+			}
+			
+			private function uploadFault(event : VineUploadEvent) : void
+			{
+				finishUploading();
+			}
+			
+			private function uploadCancel(event : VineUploadEvent) : void
+			{
+				finishUploading();
+			}
+			
+			private function finishUploading() : void
+			{
+				serverItemList.selectedIndex = parentApplication.gsSimStudioModel.selectedServerIdx;
+				parentApplication.isFileTransfering = false;
+			}
+			
+			private function onServerComboChange(ev:Event):void{
+				var selectedIndex :Number= serverItemList.selectedIndex;
+				var o:Object = null;
+				o = ev.target.selectedItem;
+				parentApplication.service.browseResource(o.url, selectedIndex);
+			}
+
+		]]>
+	</mx:Script>
+	
+	<code:MDICanvas id="mdiCanvas" width="100%" height="100%" backgroundColor="#FFFFFF" backgroundAlpha="0">
+		<mx:VBox width="100%">
+			<mx:HBox>
+				<mx:VBox>
+					<mx:Label text="{resourceManager.getString('ExperimentEditor', 'Workload')}"/>
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.workloadFileLocationItemList}" rowHeight="35" id="workloadFilesDG" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fileName" headerText="Name"/>
+							<mx:DataGridColumn headerText="{resourceManager.getString('ExperimentEditor', 'Actions')}" width="105">
+								<mx:itemRenderer>
+									<mx:Component>
+										<mx:HBox paddingLeft="4">
+											<!--
+											-<mx:Button label="{resourceManager.getString('ExperimentEditor', 'View')}" toolTip="{resourceManager.getString('ExperimentEditor', 'ViewTooltip')}" click="outerDocument.viewWorkload()" height="30" paddingLeft="8"/>
+											-->
+											<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Add')}" toolTip="{resourceManager.getString('ExperimentEditor', 'AddTooltip')}" click="outerDocument.addItemToWorkspace(outerDocument.workloadFilesDG, parentApplication.experimentEditor.workspaceWorkloadsFileList)" height="30"/>
+											<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Remove')}" toolTip="{resourceManager.getString('ExperimentEditor', 'RemoveTooltip')}" click="outerDocument.removeFileItem(outerDocument.workloadFilesDG)" height="30"/>
+										</mx:HBox>
+									</mx:Component>
+								</mx:itemRenderer>
+							</mx:DataGridColumn>
+						</mx:columns>
+					</mx:DataGrid>
+					<mx:Button id="newWorkloadFile" click="addNewWorkloadFile()" toolTip="{resourceManager.getString('ExperimentEditor', 'AddFile')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Upload')}"/>
+				</mx:VBox>
+				<mx:VBox>
+					<mx:Label text="{resourceManager.getString('ExperimentEditor', 'NetworkTopology')}"/>
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.topologiesFileLocationItemList}" rowHeight="35" id="topologyFilesDG" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fileName" headerText="Name"/>
+							<mx:DataGridColumn headerText="{resourceManager.getString('ExperimentEditor', 'Actions')}" width="105">
+								<mx:itemRenderer>
+									<mx:Component>
+										<mx:HBox paddingLeft="4">
+											<!--
+											<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Load')}" toolTip="{resourceManager.getString('ExperimentEditor', 'LoadTooltip')}" click="outerDocument.loadTopology()" height="30" paddingLeft="8"/>
+											-->
+											<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Add')}" toolTip="{resourceManager.getString('ExperimentEditor', 'AddTooltip')}" click="outerDocument.addItemToWorkspace(outerDocument.topologyFilesDG, parentApplication.experimentEditor.workspaceTopologiesFileList)" height="30"/>
+											<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Remove')}" toolTip="{resourceManager.getString('ExperimentEditor', 'RemoveTooltip')}" click="outerDocument.removeFileItem(outerDocument.topologyFilesDG)" height="30"/>
+										</mx:HBox>
+									</mx:Component>
+								</mx:itemRenderer>
+							</mx:DataGridColumn>
+						</mx:columns>
+					</mx:DataGrid>
+					<mx:Button id="newTopologyFile" click="addNewTopologyFile()" toolTip="{resourceManager.getString('ExperimentEditor', 'AddFile')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Upload')}"/>
+				</mx:VBox>
+				<mx:VBox>
+					<mx:Label text="{resourceManager.getString('ExperimentEditor', 'ResourceDescription')}"/>
+					<!--<mx:DataGrid dataProvider="{resourceFiles}" rowHeight="35" id="resourceFilesDG" >-->
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.resourcesFileLocationItemList}" rowHeight="35" id="resourceFilesDG" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fileName" headerText="Name"/>
+							<mx:DataGridColumn headerText="{resourceManager.getString('ExperimentEditor', 'Actions')}" width="105">
+								<mx:itemRenderer>
+									<mx:Component>
+										<mx:HBox paddingLeft="4">
+											<!--
+											<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Load')}" toolTip="{resourceManager.getString('ExperimentEditor', 'LoadTooltip')}" click="outerDocument.loadResources()" height="30" paddingLeft="8"/>
+											-->
+											<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Add')}" toolTip="{resourceManager.getString('ExperimentEditor', 'AddTooltip')}" click="outerDocument.addItemToWorkspace(outerDocument.resourceFilesDG, parentApplication.experimentEditor.workspaceResourcesFileList)" height="30"/>
+											<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Remove')}" toolTip="{resourceManager.getString('ExperimentEditor', 'RemoveTooltip')}" click="outerDocument.removeFileItem(outerDocument.resourceFilesDG)" height="30"/>
+										</mx:HBox>
+									</mx:Component>
+								</mx:itemRenderer>
+							</mx:DataGridColumn>
+						</mx:columns>
+					</mx:DataGrid>
+					<mx:Button id="newResourceFile" click="addNewResourceFile()" toolTip="{resourceManager.getString('ExperimentEditor', 'AddFile')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Upload')}"/>
+				</mx:VBox>
+			</mx:HBox>
+			<mx:VBox visible="{showDebug}" includeInLayout="{showDebug}">
+				<mx:HBox>
+					<mx:VBox>
+						<mx:ComboBox id="serverItemList"
+							dataProvider="{parentApplication.gsSimStudioModel.serverLocationItemList}"
+							width="200" y="150" change="onServerComboChange(event)"
+						/>
+					</mx:VBox>
+				</mx:HBox>
+			</mx:VBox>
+		</mx:VBox>
+	</code:MDICanvas>
+</mx:Module>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/ExperimentPropertiesPanel.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/ExperimentPropertiesPanel.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/ExperimentPropertiesPanel.mxml	(revision 15)
@@ -0,0 +1,424 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Module xmlns="flexlib.mdi.containers.*" xmlns:mx="http://www.adobe.com/2006/mxml" label="{resourceManager.getString('ExperimentEditor', 'CreateNewExperiment')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.flare.query.StringUtil;
+			import gssim.gssimstudio.editor.gssim.experiment.ExperimentProperties;
+			import gssim.gssimstudio.editor.gssim.experiment.FileProxy;
+			import gssim.gssimstudio.editor.script.utils.ConjunctionArray;
+			import gssim.gssimstudio.editor.script.views.ViewsHelper;
+			import gssim.gssimstudio.editor.views.ExperimentEditor;
+			
+			import mx.collections.ArrayCollection;
+			import mx.controls.Alert;
+			import mx.controls.List;
+			import mx.core.IUIComponent;
+			import mx.events.CloseEvent;
+			import mx.events.ListEvent;
+			
+			private var editedExperiment : ExperimentProperties;
+			
+			public function isFormValid() : Boolean
+			{
+				if (gridSchedulingPlugin.selectedItem.label == "(...)") return false;
+				if (localGridPlugin.selectedItem.label == "(...)") return false;
+				if (experimentName.text == null || experimentName.text == "") return false;
+				if (experimentRuns.value < 1) return false;
+				if ( (workloadFile.text == null || workloadMissingImage.visible ) && !workloadSelectedCB.selected) return false;
+				if ( (resourceDescriptionFile.text == null || resourceMissingImage.visible ) && !resourceSelectedCB.selected) return false;
+				if ( topologyCB.selected && (networkTopologyFile.text == null || topologyMissingImage.visible ) && !topologySelectedCB.selected) return false;
+				return true;
+			}
+			
+			public function createExperiment() : void
+			{
+				if (!isFormValid()) return;
+				var exp : ExperimentProperties;
+				var list : ArrayCollection = new ArrayCollection();
+				if (editedExperiment != null) exp = editedExperiment;
+				else exp = new ExperimentProperties();
+				if (workloadFile.text != null && !workloadSelectedCB.selected)
+					exp.setWorkloadFile(workloadFile.text);
+				if (networkTopologyFile.text != null && topologyCB.selected && !topologySelectedCB.selected)
+					exp.setTopologyFile(networkTopologyFile.text);
+				if (resourceDescriptionFile.text != null && !resourceSelectedCB.selected)
+					exp.setResourceFile(resourceDescriptionFile.text);
+				exp.name = experimentName.text;
+				exp.setRuns(experimentRuns.value);
+				exp.setGlobal(gridSchedulingPlugin.selectedItem);
+				exp.setLocal(localGridPlugin.selectedItem);
+				exp.setExec(executionTimeEstimationPlugin.selectedItem);
+				if (workloadSelectedCB.selected)
+				{
+					for each (var workload : Object in parentApplication.experimentEditor.workspaceWorkloadsFileList)
+					{
+						var inner : ExperimentProperties = exp.clone();
+						inner.setWorkloadFile(workload.fileName);
+						list.addItem(inner);
+					}
+				}
+				else
+				{
+					list.addItem(exp);
+				}
+				if (resourceSelectedCB.selected)
+				{
+					var iterR : int = 0;
+					var innerListR : ArrayCollection = new ArrayCollection();
+					for each (var resource : Object in parentApplication.experimentEditor.workspaceResourcesFileList)
+					{
+						var innerR : ExperimentProperties;
+						for each (var propR : ExperimentProperties in list)
+						{
+							if (iterR == 0) innerR = propR;
+							else innerR = propR.clone();
+							innerR.setResourceFile(resource.fileName);
+							if (iterR != 0) innerListR.addItem(innerR);
+						}
+						iterR++;
+					}
+					list.addAll(innerListR);
+				}
+				if (topologySelectedCB.selected)
+				{
+					var iterT : int = 0;
+					var innerListT : ArrayCollection = new ArrayCollection();
+					for each (var topology : Object in parentApplication.experimentEditor.workspaceTopologiesFileList)
+					{
+						var innerT : ExperimentProperties;
+						for each (var propT : ExperimentProperties in list)
+						{
+							if (iterT == 0) innerT = propT;
+							else innerT = propT.clone();
+							innerT.setTopologyFile(topology.fileName);
+							if (iterT != 0) innerListT.addItem(innerT);
+						}
+						iterT++;
+					}
+					list.addAll(innerListT);
+				}
+				
+				for each (var prop : ExperimentProperties in list)
+				{
+					if (editedExperiment == null) ExperimentEditor.experiments.addItem(prop);
+				}
+				editedExperiment = null;
+			}
+			
+			public function loadExperiment(exp : ExperimentProperties) : void
+			{
+				editedExperiment = exp;
+				experimentName.text = exp.name;
+				experimentRuns.value = exp.runs;
+				if (exp.getProperty(ExperimentProperties.gridSchedulingPlugin) != null)
+				for (var global : int = 0; global <  gridSchedulingPlugin.dataProvider.length; global++)
+				{
+					if (gridSchedulingPlugin.dataProvider[global].label == exp.global) gridSchedulingPlugin.selectedIndex = global;
+				}
+				if (exp.getProperty(ExperimentProperties.localAllocPolicyPlugin) != null)
+				for (var local : int = 0; local <  localGridPlugin.dataProvider.length; local++)
+				{
+					if (localGridPlugin.dataProvider[local].label == exp.local) localGridPlugin.selectedIndex = local;
+				}
+				if (exp.getProperty(ExperimentProperties.execTimeEstimationPlugin) != null)
+				for (var exec : int = 0; exec <  executionTimeEstimationPlugin.dataProvider.length; exec++)
+				{
+					if (executionTimeEstimationPlugin.dataProvider[exec].label == exp.exec) executionTimeEstimationPlugin.selectedIndex = exec;
+				}
+				plugin_dragDropHandler(null, gridSchedulingPluginCompatibleList, localGridPlugin, gridSchedulingPluginAC);
+				plugin_dragDropHandler(null, localGridPluginCompatibleList, gridSchedulingPlugin, localGridPluginAC);
+				workloadFile.text = exp.workload;
+				resourceDescriptionFile.text = exp.resources;
+				if (exp.topology != null)
+				{
+					networkTopologyFile.text = exp.topology;	
+					topologyCB.selected = true;
+				}
+			}
+			
+			public function loadFromHashmap(map : Object) : void
+			{
+				if (map.hasOwnProperty("gridschedulingpluginname"))
+				{
+					for each (var obj : Object in gridSchedulingPlugin.dataProvider)
+					{
+						if (obj.data == map["gridschedulingpluginname"])
+						{
+							gridSchedulingPlugin.selectedItem = obj;
+						}
+					}
+				}
+				if (map.hasOwnProperty("localallocpolicypluginname"))
+				{
+					for each (var obj : Object in localGridPlugin.dataProvider)
+					{
+						if (obj.data == map["localallocpolicypluginname"]) localGridPlugin.selectedItem = obj; 
+					}
+				}
+				if (map.hasOwnProperty("exectimeestimationpluginname"))
+				{
+					for each (var obj : Object in executionTimeEstimationPlugin.dataProvider)
+					{
+						if (obj.data == map["exectimeestimationpluginname"]) executionTimeEstimationPlugin.selectedItem = obj; 
+					}
+				}
+				if (map.hasOwnProperty("numberofsimulations"))
+				{
+					experimentRuns.value = map["numberofsimulations"];
+				}
+				if (map.hasOwnProperty("readscenario.workloadfilename"))
+				{
+					workloadFile.text = StringUtil.substring(map["readscenario.workloadfilename"], 16);
+					networkTopologyFile_changeHandler(null);
+				}
+				if (map.hasOwnProperty("resdesc"))
+				{
+					resourceDescriptionFile.text = StringUtil.substring(map["resdesc"], 16);
+					resourceDescriptionFile_changeHandler(null);
+				}
+			}
+			
+			protected function containsItemId(array : ArrayCollection, id : String) : Boolean
+			{
+				for each (var item : String in array)
+				{
+					if (item == id) return true;
+				}
+				return false;
+			}
+			
+			protected var gridSchedulingPluginCompatibleList : ConjunctionArray = new ConjunctionArray;
+			protected var localGridPluginCompatibleList : ConjunctionArray = new ConjunctionArray;
+			
+			protected function plugin_dragDropHandler(event:ListEvent, compatibleList: ConjunctionArray, data : ComboBox, AC : ArrayCollection):void
+			{
+				compatibleList.clear();
+				var obj : Object = null;
+				compatibleList.addItem(data.selectedItem.compatible.toString().split(','));
+				AC.refresh();
+			}
+			
+			protected function gridSchedulingPluginFilterFunc(item:Object):Boolean
+			{
+				if (gridSchedulingPluginCompatibleList.data.length == 0) return true;
+				return containsItemId(gridSchedulingPluginCompatibleList.data, item.id);
+			}
+			
+			protected function localGridPluginFilterFunc(item:Object):Boolean
+			{
+				if (localGridPluginCompatibleList.data.length == 0) return true;
+				return containsItemId(localGridPluginCompatibleList.data, item.id);
+			}
+			
+			private function showAboutBox(title : String, text : String) : void
+			{
+				if (text != null)
+				{
+					var popup : PluginDescriptionPopup = new PluginDescriptionPopup();
+					popup.show(title, text, parentApplication.experimentEditor);
+				}
+			}
+
+			protected function topologyCB_changeHandler(event:Event):void
+			{
+				if (!topologyCB.selected) topologySelectedCB.selected = false;
+			}
+
+
+			protected function resourceDescriptionFile_changeHandler(event:ListEvent):void
+			{
+				for (var i : int = 0; i < parentApplication.gsSimStudioModel.resourcesFileLocationItemList.length; i++)
+				{
+					if (parentApplication.gsSimStudioModel.resourcesFileLocationItemList[i].fileName == resourceDescriptionFile.text)
+					{
+						resourceMissingImage.visible = false;
+						return;
+					}
+				}
+				resourceMissingImage.visible = true;
+			}
+
+
+			protected function networkTopologyFile_changeHandler(event:ListEvent):void
+			{
+				if (networkTopologyFile.text == null)
+				{
+					topologyMissingImage.visible = false;
+					return;
+				}
+				for (var i : int = 0; i < parentApplication.gsSimStudioModel.topologiesFileLocationItemList.length; i++)
+				{
+					if (parentApplication.gsSimStudioModel.topologiesFileLocationItemList[i].fileName == networkTopologyFile.text)
+					{
+						topologyMissingImage.visible = false;
+						return;
+					}
+				}
+				topologyMissingImage.visible = true;
+			}
+
+
+			protected function workloadFile_changeHandler(event:ListEvent):void
+			{
+				for (var i : int = 0; i < parentApplication.gsSimStudioModel.workloadFileLocationItemList.length; i++)
+				{
+					if (parentApplication.gsSimStudioModel.workloadFileLocationItemList[i].fileName == workloadFile.text)
+					{
+						workloadMissingImage.visible = false;
+						return;
+					}
+				}
+				workloadMissingImage.visible = true;
+			}
+
+		]]>
+	</mx:Script>
+	<mx:Model id="gridSchedulingPluginModel">
+		<obj>
+			<item label="GridschedulingFCFSRR" data="example.gridplugin.GridRoundRobinPlugin" id="1" compatible="1,2,3,4,5"/>
+			<item label="GridschedulingARFCFS" data="example.gridplugin.??" id="2" compatible="1,3"/>
+			<item label="GridschedulingARNRDijkstra" data="example.gridplugin.GridARNRDijkstra" id="3" compatible="1"/>
+			<item label="GridARAllSlots" data="example.gridplugin.GridARAllSlots" id="4" compatible="1"/>
+			<item label="GridARFirstFit" data="example.gridplugin.GridARFirstFit" id="5" compatible="1"/>
+			<item label="GridARNRSpecificPath" data="example.gridplugin.GridARNRSpecificPath" id="6" compatible="1"/>
+			<item label="ARGraham" data="example.gridplugin.ARGraham" id="7" compatible="6"/>
+		</obj>
+	</mx:Model>
+	<mx:ArrayCollection id="gridSchedulingPluginAC" source="{parentApplication.gsSimStudioModel.globalPluginList.toArray()}" filterFunction="gridSchedulingPluginFilterFunc"/>
+	
+	<mx:Model id="localGridPluginModel">
+		<obj>
+			<item label="FCFSAllocPolicy" data="example.localplugin.FCFSLocalPlugin" id="1" compatible="1,2,3,4,5,6"/>
+			<item label="LocalGridPluginAR" data="example.localplugin.??" id="2" compatible="1"/>
+			<item label="BaseLocalPlugin" data="example.localplugin.BaseLocalPlugin" id="3" compatible="1,2"/>
+			<item label="BaseLocalARPlugin" data="example.localplugin.BaseLocalARPlugin" id="4" compatible="1"/>
+			<item label="ARAllSlots" data="example.localplugin.ARAllSlots" id="5" compatible="1"/>
+			<item label="ARFirstFit" data="example.localplugin.ARFirstFit" id="6" compatible="7"/>
+		</obj>
+	</mx:Model>
+	<mx:ArrayCollection id="localGridPluginAC" source="{parentApplication.gsSimStudioModel.localPluginList.toArray()}" filterFunction="localGridPluginFilterFunc"/>
+	
+	<mx:Model id="executionTimeEstimationPluginModel">
+		<obj>
+			<item label="ExecTimeEstimationPluginImpl" data="example.timeestimation.ExecTimeEstimationPlugin"/>
+		</obj>
+	</mx:Model>
+	<mx:ArrayCollection id="executionTimeEstimationPluginAC" source="{new Array(executionTimeEstimationPluginModel.item)}"/>
+	
+	<mx:VBox>
+		<mx:HBox>
+			<mx:VBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('ExperimentEditor', 'Name')}"/>
+					<components:QuickTooltipImage height="16" width="16"
+						toolTip="{resourceManager.getString('Help', 'ExperimentName')}"
+						source="assets/icon/HelpIcon.png"/>
+				</mx:HBox>				
+				<mx:TextInput id="experimentName" width="250" restrict="0-9a-zA-Z"/>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('ExperimentEditor', 'Runs')}"/>
+					<components:QuickTooltipImage height="16" width="16"
+							  toolTip="{resourceManager.getString('Help', 'NumberOfSimulations')}"
+							  source="assets/icon/HelpIcon.png"/>
+				</mx:HBox>	
+				<mx:NumericStepper id="experimentRuns" width="250" minimum="1" />
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('ExperimentEditor', 'GridScheduling')}"/>
+					<components:QuickTooltipImage height="16" width="16"
+							  toolTip="{resourceManager.getString('Help', 'GridScheduling')}"
+							  source="assets/icon/HelpIcon.png"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:ComboBox id="gridSchedulingPlugin" dataProvider="{gridSchedulingPluginAC}" width="170"
+								 toolTip="{resourceManager.getString('ExperimentEditor', 'GridSchedulingTooltip')}"
+								 change="plugin_dragDropHandler(event, localGridPluginCompatibleList, gridSchedulingPlugin, localGridPluginAC)"/>
+					<mx:Button click="showAboutBox(gridSchedulingPlugin.selectedItem.label, gridSchedulingPlugin.selectedItem.description)" label="{resourceManager.getString('ExperimentEditor', 'About')}"
+							   width="72" enabled="{gridSchedulingPlugin.selectedItem != null &amp;&amp; gridSchedulingPlugin.selectedItem.description != null}"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('ExperimentEditor', 'LocalGrid')}"/>
+					<components:QuickTooltipImage height="16" width="16"
+							  toolTip="{resourceManager.getString('Help', 'LocalGrid')}"
+							  source="assets/icon/HelpIcon.png"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:ComboBox id="localGridPlugin" dataProvider="{localGridPluginAC}" width="170"
+								 toolTip="{resourceManager.getString('ExperimentEditor', 'LocalGridTooltip')}"
+								 change="plugin_dragDropHandler(event, gridSchedulingPluginCompatibleList, localGridPlugin, gridSchedulingPluginAC)"/>
+					<mx:Button click="showAboutBox(localGridPlugin.selectedItem.label, localGridPlugin.selectedItem.description)" label="{resourceManager.getString('ExperimentEditor', 'About')}"
+							   width="72" enabled="{localGridPlugin.selectedItem != null &amp;&amp; localGridPlugin.selectedItem.description != null}"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Label text="{resourceManager.getString('ExperimentEditor', 'ExecutionTimeEstimation')}"/>
+					<components:QuickTooltipImage height="16" width="16"
+							  toolTip="{resourceManager.getString('Help', 'ExecutionTimeEstimation')}"
+							  source="assets/icon/HelpIcon.png"/>
+				</mx:HBox>	
+				<mx:ComboBox id="executionTimeEstimationPlugin" dataProvider="{executionTimeEstimationPluginAC}" width="250"
+							 toolTip="{resourceManager.getString('ExperimentEditor', 'ExecutionTimeEstimationTooltip')}"/>
+			</mx:VBox>
+			<mx:VBox label="{resourceManager.getString('ExperimentEditor', 'Files')}">
+				<mx:HBox>
+					<mx:HBox>
+						<mx:Label text="{resourceManager.getString('ExperimentEditor', 'Workload')}"/>
+						<components:QuickTooltipImage height="16" width="16"
+								  toolTip="{resourceManager.getString('Help', 'Workload')}"
+								  source="assets/icon/HelpIcon.png"/>
+					</mx:HBox>
+					<mx:CheckBox id="workloadSelectedCB" label="{resourceManager.getString('ExperimentEditor', 'UseSelectedFiles')}" height="16"
+								 enabled="{!topologySelectedCB.selected &amp;&amp; !resourceSelectedCB.selected}"/>
+					<!--
+					<mx:Button label="{resourceManager.getString('ExperimentEditor', 'View')}" click="workloadView()" />
+					-->
+				</mx:HBox>
+				<mx:HBox>
+					<mx:ComboBox id="workloadFile" labelField="fileName" dataProvider="{parentApplication.experimentEditor.workspaceWorkloadsFileList}" width="250"
+								 toolTip="{resourceManager.getString('ExperimentEditor', 'WorkloadTooltip')}" enabled="{!workloadSelectedCB.selected}"
+								 change="workloadFile_changeHandler(event)"/>
+					<components:QuickTooltipImage height="16" width="16" id="workloadMissingImage" visible="false"
+												  source="assets/deleteButton.png"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:HBox>
+						<mx:CheckBox id="topologyCB" label="{resourceManager.getString('ExperimentEditor', 'NetworkTopology')}" height="16"
+									 change="topologyCB_changeHandler(event)"/>
+						<components:QuickTooltipImage height="16" width="16"
+								  toolTip="{resourceManager.getString('Help', 'NetworkTopology')}"
+								  source="assets/icon/HelpIcon.png"/>
+					</mx:HBox>
+					<mx:CheckBox id="topologySelectedCB" label="{resourceManager.getString('ExperimentEditor', 'UseSelectedFiles')}"
+								 enabled="{topologyCB.selected &amp;&amp; !resourceSelectedCB.selected &amp;&amp; !workloadSelectedCB.selected}" height="16"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:ComboBox id="networkTopologyFile" labelField="fileName" dataProvider="{parentApplication.experimentEditor.workspaceTopologiesFileList}" width="250"
+							 toolTip="{resourceManager.getString('ExperimentEditor', 'NetworkTopologyTooltip')}"
+							 enabled="{topologyCB.selected &amp;&amp; !topologySelectedCB.selected}"
+							 change="networkTopologyFile_changeHandler(event)"/>
+					<components:QuickTooltipImage height="16" width="16" id="topologyMissingImage" visible="false"
+											  source="assets/deleteButton.png"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:HBox>
+						<mx:Label text="{resourceManager.getString('ExperimentEditor', 'ResourceDescription')}"/>
+						<components:QuickTooltipImage height="16" width="16"
+								  toolTip="{resourceManager.getString('Help', 'ResourceDescription')}"
+								  source="assets/icon/HelpIcon.png"/>
+					</mx:HBox>
+					<mx:CheckBox id="resourceSelectedCB" label="{resourceManager.getString('ExperimentEditor', 'UseSelectedFiles')}" height="16"
+								 enabled="{!topologySelectedCB.selected &amp;&amp; !workloadSelectedCB.selected}"/>
+				</mx:HBox>
+				
+				<mx:HBox>
+					<mx:ComboBox id="resourceDescriptionFile" labelField="fileName" dataProvider="{parentApplication.experimentEditor.workspaceResourcesFileList}" width="250"
+								 toolTip="{resourceManager.getString('ExperimentEditor', 'ResourceDescriptionTooltip')}"
+								 enabled="{!resourceSelectedCB.selected}" change="resourceDescriptionFile_changeHandler(event)"/>
+					<components:QuickTooltipImage height="16" width="16" id="resourceMissingImage" visible="false"
+												  source="assets/deleteButton.png"/>
+				</mx:HBox>
+				<mx:HBox>
+					<mx:Button id="addExperiment" click="createExperiment();" toolTip="{resourceManager.getString('ExperimentEditor', 'AddTooltip')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Add')}"/>
+				</mx:HBox>
+			</mx:VBox>
+		</mx:HBox>
+	</mx:VBox>
+</mx:Module>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/WorkloadFastViewWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/WorkloadFastViewWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/WorkloadFastViewWindow.mxml	(revision 15)
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindow xmlns="flexlib.mdi.containers.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" title="{resourceManager.getString('ExperimentEditor', 'Workload')}" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	<mx:Script>
+		<![CDATA[
+			import mx.controls.dataGridClasses.DataGridColumn;
+			import gssim.gssimstudio.editor.gssim.workload.swf.WorkloadSWF;
+			import mx.collections.ArrayCollection;
+			import gssim.gssimstudio.editor.gssim.workload.PreferenceParameter;
+			import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+			import gssim.gssimstudio.editor.gssim.workload.Preference;
+			
+			[Bindable]
+			private var workload : WorkloadSWF;
+			
+			public function setWorkload(workload : WorkloadSWF) : void
+			{
+				this.workload = workload;
+			}
+			
+			private function dynamicNameTranslate(item : Object, column : DataGridColumn) : String
+			{
+				return resourceManager.getString("ExperimentEditor", item.name);
+			}
+			
+		]]>
+	</mx:Script>
+	<mx:TabNavigator paddingLeft="5" width="100%" height="100%">
+		<mx:VBox paddingLeft="5" paddingTop="5" paddingRight="5" paddingBottom="5" width="100%" height="100%" label="{resourceManager.getString('ExperimentEditor', 'Header')}">
+			<mx:TextArea width="100%" height="100%" id="headers" text="{workload.headers}"
+				/>
+		</mx:VBox>
+		<mx:VBox paddingLeft="5" paddingTop="5" paddingRight="5" paddingBottom="5" width="100%" height="100%" label="{resourceManager.getString('ExperimentEditor', 'Statistics')}">
+			<mx:DataGrid id="dg_stats" width="100%" height="100%" dataProvider="{workload.statistics}" >
+				<mx:columns>
+					<mx:DataGridColumn dataField="name" labelFunction="dynamicNameTranslate" headerText="{resourceManager.getString('ExperimentEditor', 'Name')}"/>
+					<mx:DataGridColumn dataField="value" headerText="{resourceManager.getString('ExperimentEditor', 'Value')}"/>
+				</mx:columns>
+			</mx:DataGrid>
+		</mx:VBox>
+		<mx:VBox paddingLeft="5" paddingTop="5" paddingRight="5" paddingBottom="5" width="100%" height="100%" label="{resourceManager.getString('ExperimentEditor', 'WorkloadData')}">
+			<mx:DataGrid id="dg" width="100%" height="100%" dataProvider="{workload.jobs}" >
+				<mx:columns>
+					<mx:DataGridColumn dataField="Field1" headerText="{resourceManager.getString('ExperimentEditor', 'Field1')}"/>
+					<mx:DataGridColumn dataField="Field2" headerText="{resourceManager.getString('ExperimentEditor', 'Field2')}"/>
+					<mx:DataGridColumn dataField="Field3" headerText="{resourceManager.getString('ExperimentEditor', 'Field3')}"/>
+					<mx:DataGridColumn dataField="Field4" headerText="{resourceManager.getString('ExperimentEditor', 'Field4')}"/>
+					<mx:DataGridColumn dataField="Field5" headerText="{resourceManager.getString('ExperimentEditor', 'Field5')}"/>
+					<mx:DataGridColumn dataField="Field6" headerText="{resourceManager.getString('ExperimentEditor', 'Field6')}"/>
+					<mx:DataGridColumn dataField="Field7" headerText="{resourceManager.getString('ExperimentEditor', 'Field7')}"/>
+					<mx:DataGridColumn dataField="Field8" headerText="{resourceManager.getString('ExperimentEditor', 'Field8')}"/>
+					<mx:DataGridColumn dataField="Field9" headerText="{resourceManager.getString('ExperimentEditor', 'Field9')}"/>
+					<mx:DataGridColumn dataField="Field10" headerText="{resourceManager.getString('ExperimentEditor', 'Field10')}"/>
+					<mx:DataGridColumn dataField="Field11" headerText="{resourceManager.getString('ExperimentEditor', 'Field11')}"/>
+					<mx:DataGridColumn dataField="Field12" headerText="{resourceManager.getString('ExperimentEditor', 'Field12')}"/>
+					<mx:DataGridColumn dataField="Field13" headerText="{resourceManager.getString('ExperimentEditor', 'Field13')}"/>
+					<mx:DataGridColumn dataField="Field14" headerText="{resourceManager.getString('ExperimentEditor', 'Field14')}"/>
+					<mx:DataGridColumn dataField="Field15" headerText="{resourceManager.getString('ExperimentEditor', 'Field15')}"/>
+					<mx:DataGridColumn dataField="Field16" headerText="{resourceManager.getString('ExperimentEditor', 'Field16')}"/>
+					<mx:DataGridColumn dataField="Field17" headerText="{resourceManager.getString('ExperimentEditor', 'Field17')}"/>
+					<mx:DataGridColumn dataField="Field18" headerText="{resourceManager.getString('ExperimentEditor', 'Field18')}"/>
+				</mx:columns>
+			</mx:DataGrid>
+		</mx:VBox>
+	</mx:TabNavigator>
+</MDIWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/PluginDescriptionPopup.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/PluginDescriptionPopup.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/experiment/PluginDescriptionPopup.mxml	(revision 15)
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009" 
+		 xmlns:s="library://ns.adobe.com/flex/spark"
+		 xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
+	<fx:Declarations>
+		<!-- Place non-visual elements (e.g., services, value objects) here -->
+	</fx:Declarations>
+	<fx:Script>
+		<![CDATA[
+			import flashx.textLayout.elements.TextFlow;
+			
+			import mx.managers.PopUpManager;
+			
+			import spark.utils.TextFlowUtil;
+			
+			[Bindable]
+			private var text : TextFlow;
+			
+			public function show(title : String, description : String, parent : DisplayObject) : void
+			{
+				text = TextFlowUtil.importFromString(description);
+				this.title = title;
+				PopUpManager.addPopUp(this, parent, true);
+				PopUpManager.centerPopUp(this);
+			}
+			
+			private function close() : void
+			{
+				PopUpManager.removePopUp(this);
+			}
+		]]>
+	</fx:Script>
+	<mx:VBox width="100%" height="100%">
+		<s:TextArea id="descriptionTA" width="100%" height="100%" textFlow="{text}" editable="false"/>
+		<mx:Button click="close()" label="{resourceManager.getString('ExperimentEditor', 'Close')}"/>
+	</mx:VBox>
+</s:Panel>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/ExperimentDataGroup.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/ExperimentDataGroup.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/ExperimentDataGroup.mxml	(revision 15)
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"
+		 xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	<mx:Script>
+		<![CDATA[
+			//import gssim.gssimstudio.db.dao.data.Experiment;
+			import gssim.gssimstudio.editor.gssim.editors.archive.ExperimentStatisticsWindow;
+			import gssim.gssimstudio.editor.script.views.ViewsHelper;
+			
+			[Bindable]
+			private var experiment : Object;
+			
+			public function loadExperiment(exp : Object, hideButtons : Boolean = false) : void
+			{
+				if (hideButtons)
+				{
+					viewStatsButton.visible = false;
+					viewStatsButton.includeInLayout = false;
+				}
+				else
+				{
+					viewStatsButton.visible = true;
+					viewStatsButton.includeInLayout = true;
+				}
+				experiment = exp;
+				//call service to load experiment data
+			}
+			
+			public function viewStats() : void
+			{
+				var window : ExperimentStatisticsWindow = new ExperimentStatisticsWindow();
+				window.loadExperiment(experiment);
+				ViewsHelper.ArchiveCanvas.windowManager.add(window);
+			}
+			
+			public function saveDetails() : void
+			{
+				//fixme - allow to change other parameters (i.e. commision date)
+				parentApplication.service.updateExperiment(experiment.PK, -1, -1, ExperimentName.text, null, ExperimentComment.text, null, -1);
+				experiment = null;
+			}
+			
+			public function deleteExperiment() : void
+			{
+				parentApplication.service.deleteExperiment(experiment.PK);
+			}
+			
+		]]>
+	</mx:Script>
+	<mx:HBox>
+		<mx:Label text="{resourceManager.getString('ArchiveViewer', 'Name') + ':'}"/>
+		<mx:TextInput id="ExperimentName" text="{experiment.name}" restrict="0-9a-zA-Z"/>
+		<mx:Label text=" ["/>
+		<mx:Label id="ExperimentFolder" text="{parentApplication.gsSimStudioModel.metaexperimentList[experiment.metaexpId]}"/>
+		<mx:Label text="]"/>
+	</mx:HBox>
+	<mx:HBox>
+		<mx:Label text="{resourceManager.getString('ArchiveViewer', 'CommissionDate') + ':'}"/>
+		<mx:Label id="CommissionDate" text="{experiment.commissionDate}"/>
+	</mx:HBox>
+	<mx:VBox width="100%">
+		<mx:Label text="{resourceManager.getString('ArchiveViewer', 'Comment') + ':'}"/>
+		<mx:TextArea id="ExperimentComment" width="100%" height="120" text="{experiment.description}"/>
+	</mx:VBox>
+	<mx:HBox>
+		<mx:Button id="viewStatsButton" label="{resourceManager.getString('ArchiveViewer', 'View')}" click="viewStats()" />
+		<mx:Button label="{resourceManager.getString('ArchiveViewer', 'Save')}" click="saveDetails()" />
+		<mx:Button label="{resourceManager.getString('ArchiveViewer', 'Delete')}" click="deleteExperiment()" />
+	</mx:HBox>
+</mx:VBox>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/GroupStatisticsWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/GroupStatisticsWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/GroupStatisticsWindow.mxml	(revision 15)
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindow xmlns="flexlib.mdi.containers.*"
+		   xmlns:components="gssim.gssimstudio.editor.gssim.components.*"
+		   xmlns:s="library://ns.adobe.com/flex/spark"
+		   xmlns:mx="library://ns.adobe.com/flex/mx"
+		   title="Stats view"
+		   xmlns:fx="http://ns.adobe.com/mxml/2009" 
+		   width="80%" height="70%"
+		   creationComplete="initWindow()"
+		   xmlns:charts="gssim.gssimstudio.editor.charts.*"
+		   xmlns:archive="gssim.gssimstudio.editor.gssim.editors.archive.*">
+<fx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.charts.ExperimentComparisonChart;
+		
+		import mx.collections.ArrayCollection;
+		import mx.events.FlexEvent;
+		
+		import org.vinetoolkit.vine.rpc.remoting.VineRemoteObjectProxy;
+		
+		protected var experiments : ArrayCollection;
+		
+		public function init(experiments : ArrayCollection):void
+		{
+			this.experiments = experiments;
+		}
+
+		protected function initWindow():void
+		{
+			var viewer : ExperimentComparisonChart = new ExperimentComparisonChart();
+			viewer.experiments = experiments;
+			var i : int = (parentApplication.gsSimStudioModel.comparisonComponents != null
+				? parentApplication.gsSimStudioModel.comparisonComponents.length
+				: 0);
+			viewer.compId = '' + i;
+			viewer.service = new VineRemoteObjectProxy(parentApplication.service, i);
+			chart.addChild(viewer);
+			//parentApplication.bindSubmodel(viewer, 'model', parentApplication.gsSimStudioModel, 'comparisonComponents', '' + i);
+		}
+
+	]]>
+</fx:Script>
+	
+	<fx:Metadata>
+		[ResourceBundle("ArchiveViewer")]
+	</fx:Metadata>
+	
+<mx:VBox width="100%" height="100%">
+	<mx:Canvas width="100%" height="100%">
+			<mx:VBox width="100%" height="100%" id="chart" />
+	</mx:Canvas>
+</mx:VBox>
+</MDIWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/ExperimentStatisticsWindow.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/ExperimentStatisticsWindow.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/editors/archive/ExperimentStatisticsWindow.mxml	(revision 15)
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindow xmlns="flexlib.mdi.containers.*"
+		   xmlns:components="gssim.gssimstudio.editor.gssim.components.*"
+		   xmlns:s="library://ns.adobe.com/flex/spark"
+		   xmlns:mx="library://ns.adobe.com/flex/mx"
+		   title="{experiment.name} - {resourceManager.getString('ArchiveViewer', 'Details')}"
+		   xmlns:fx="http://ns.adobe.com/mxml/2009" 
+		   width="600" height="400"
+		   xmlns:charts="gssim.gssimstudio.editor.charts.*"
+		   xmlns:archive="gssim.gssimstudio.editor.gssim.editors.archive.*"
+		   creationComplete="initExperiment(event)" xmlns:experiment="gssim.gssimstudio.editor.gssim.editors.experiment.*">
+<fx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.charts.ResourceChart;
+		import gssim.gssimstudio.editor.charts.ResourceChartModel;
+		import gssim.gssimstudio.editor.gssim.topology.file.topologyReader;
+		
+		import mx.controls.Alert;
+		import mx.events.FlexEvent;
+		import mx.events.IndexChangedEvent;
+		
+		import org.vinetoolkit.vine.rpc.remoting.VineRemoteObjectProxy;
+		
+		[Bindable]
+		private var experiment : Object;
+		
+		public function loadExperiment(exp : Object) : void
+		{
+			experiment = exp;
+			if (basicExperimentData != null)
+				basicExperimentData.loadExperiment(exp, true);
+		}
+
+		protected function initExperiment(event:FlexEvent):void
+		{
+			basicExperimentData.loadExperiment(experiment, true);
+			if (experiment != null)
+				parentApplication.service.getExperimentNetworkTopology(experiment.PK);
+			var viewer : ResourceChart = new ResourceChart();
+			var i : int = (experiment != null ? experiment.PK : -1);
+			//viewer.addEventListener("configurationLoaded", configurationLoadedEventHandler);
+			viewer.expId = i;
+			viewer.expName = experiment.name;
+			viewer.service = new VineRemoteObjectProxy(parentApplication.service, i);
+			resourceChart.addChild(viewer);
+			//parentApplication.bindSubmodel(viewer, 'model', parentApplication.gsSimStudioModel, 'resourceChartComponents', '' + i);
+		}
+		
+		private function configurationLoadedEventHandler(event : Event) : void
+		{
+			//resourceChart.getChildAt(0).removeEventListener("configurationLoaded", configurationLoadedEventHandler);
+			
+			properties.loadFromHashmap(parentApplication.gsSimStudioModel.resourceChartComponents['' + experiment.PK].experimentConfiguration);
+			
+		}
+		
+		public function loadNetwork() : void
+		{
+			var r : topologyReader = new topologyReader(parentApplication.topologyEditor.objectCanvas, false);
+			r.readFromBinary(parentApplication.gsSimStudioModel.currentExperimentNetworkTopology);
+		}
+
+		protected function view_changeHandler(event:IndexChangedEvent):void
+		{
+			configurationLoadedEventHandler(null);
+		}
+
+	]]>
+</fx:Script>
+	
+	<fx:Metadata>
+		[ResourceBundle("ArchiveViewer")]
+	</fx:Metadata>
+	
+<mx:VBox width="100%" height="100%">
+	<mx:Canvas width="100%" height="100%">
+		<!--
+		<mx:HBox left="10" top="10">
+			<components:IconButton  skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+									height="48" width="48" click="{view.selectedChild = experimentData}"
+									iconUp="assets/infoButton.png"/>
+			<components:IconButton  skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+								   height="48" width="48" click="{view.selectedChild = resourceChart}"
+								   iconUp="assets/infoButton.png"/>
+			<components:IconButton  skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+									height="48" width="48" click="{view.selectedChild = taskChart}"
+									iconUp="assets/infoButton.png"/>
+			<components:IconButton  skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+									height="48" width="48" click="{view.selectedChild = lineChart}"
+									iconUp="assets/infoButton.png"/>
+			<components:IconButton  skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+									height="48" width="48" click="{view.selectedChild = anyChart}"
+									iconUp="assets/infoButton.png"/>
+		</mx:HBox>
+		-->
+		<mx:HBox right="10" top="10">
+			<components:IconButton  skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+									height="48" width="48" visible="false" includeInLayout="false"
+									iconUp="assets/icon/OpenProperties.png"/>
+			<components:IconButton  skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin" click="loadNetwork()"
+									height="48" width="48" visible="{parentApplication.gsSimStudioModel.currentExperimentNetworkTopology != null}"
+									iconUp="assets/icon/NetworkEditor.png"/>
+			<components:IconButton  skinClass="gssim.gssimstudio.editor.gssim.skins.IconButtonSkin"
+									height="48" width="48" visible="false" includeInLayout="false"
+									iconUp="assets/icon/OpenFile.png"/>
+		</mx:HBox>
+		<mx:TabNavigator id="view" width="100%" height="100%" top="56" creationPolicy="all" change="view_changeHandler(event)">
+			<mx:VBox width="100%" height="100%" id="experimentData" label="{resourceManager.getString('ArchiveViewer', 'Basic')}">
+				<archive:ExperimentDataGroup id="basicExperimentData" left="5" top="5"/>
+			</mx:VBox>
+			<mx:VBox label="{resourceManager.getString('ArchiveViewer', 'Configuration')}">
+				<experiment:ExperimentPropertiesPanel id="properties"/>
+			</mx:VBox>
+			<mx:VBox width="100%" height="100%" id="resourceChart" label="{resourceManager.getString('ArchiveViewer', 'Resource')}">
+				<!--<charts:ResourceViewer width="100%" height="100%" />-->
+			</mx:VBox>
+			<!--
+			<mx:VBox width="100%" height="100%" id="taskChart" label="{resourceManager.getString('ArchiveViewer', 'Task')}">
+				<charts:ScheduleViewer width="100%" height="100%" />
+				<mx:Label text="task chart"/>
+			</mx:VBox>
+			<mx:VBox width="100%" height="100%" id="lineChart" label="{resourceManager.getString('ArchiveViewer', 'Line')}">
+				<charts:ScheduleViewer width="100%" height="100%" />
+				<mx:Label text="line chart"/>
+			</mx:VBox>
+			<mx:VBox width="100%" height="100%" id="anyChart" label="{resourceManager.getString('ArchiveViewer', 'Other')}">
+				<charts:ScheduleViewer width="100%" height="100%" />
+				<mx:Label text="other chart"/>
+			</mx:VBox>-->
+		</mx:TabNavigator>
+	</mx:Canvas>
+</mx:VBox>
+</MDIWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/minimap/Minimap.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/minimap/Minimap.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/minimap/Minimap.as	(revision 15)
@@ -0,0 +1,193 @@
+package gssim.gssimstudio.editor.gssim.minimap
+{
+	import com.degrafa.Surface;
+	import com.degrafa.core.utils.ColorKeys;
+	
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+	import flash.geom.Matrix;
+	import flash.geom.Rectangle;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	import gssim.gssimstudio.editor.gssim.topology.ResourceObject;
+	import gssim.gssimstudio.editor.gssim.topology.UserObject;
+	
+	import mx.graphics.SolidColor;
+	import mx.graphics.SolidColorStroke;
+	
+	import spark.components.Group;
+	import spark.primitives.Ellipse;
+	import spark.primitives.Rect;
+	
+	/**
+	 * Defines minimap behaviours
+	 */
+	public class Minimap extends Surface
+	{
+		private var objects : Object; // map id -> geometry group
+				
+		private var _scaleX : Number = 16;
+		private var _scaleY : Number = 16;
+		
+		private var numberOfScreensVertical : Number;
+		private var numberOfScreensHorizontal : Number;
+		private var currentMaxWidth : Number;
+		private var currentMaxHeight : Number;
+		
+		private var visibleRectangleGroup : Group;
+		private var rectangle : Rect;
+		
+		private var targetCanvas : ObjectCanvas;
+		
+		public function Minimap()
+		{
+			objects = new Object();
+			visibleRectangleGroup = new Group(); 
+			rectangle = new Rect();
+			rectangle.x = 0;
+			rectangle.y = 0;
+			rectangle.width = 50;
+			rectangle.height = 50;
+			rectangle.radiusX = 5;
+			var rectangleFill : SolidColor = new SolidColor(ColorKeys.BLACK);
+			rectangleFill.alpha = 0.0;
+			rectangle.fill = rectangleFill;
+			var rectangleStroke : SolidColorStroke = new SolidColorStroke(ColorKeys.DARKGREEN);
+			rectangleStroke.weight = 1;
+			rectangle.stroke = rectangleStroke;
+			visibleRectangleGroup.addElement(rectangle);
+			this.addChild(visibleRectangleGroup);
+			visibleRectangleGroup.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveOnVisibleRectangleGroupEventHandler);
+			visibleRectangleGroup.addEventListener(MouseEvent.MOUSE_OUT, mouseOutOnVisibleRectangleGroupEventHandler);
+		}
+		
+		/**
+		 * Initialize the map
+		 */
+		public function init(target : ObjectCanvas) : void
+		{
+			targetCanvas = target;
+			scaleChanged();
+			target.addEventListener(ObjectCanvas.CANVAS_MOVED, targetMovedEventHandler);
+		}
+		
+		/**
+		 * The corresponding canvas was moved by mouse drag
+		 */
+		private function targetMovedEventHandler(event : Event) : void
+		{
+			updateVisibleRectanglePosition();
+		}
+
+		/**
+		 * Stops minimap drag when mouse left the visible box area
+		 */
+		private function mouseOutOnVisibleRectangleGroupEventHandler(event : MouseEvent) : void
+		{
+			visibleRectangleGroup.stopDrag();
+		}
+
+		/**
+		 * Move visible rectangle with mouse drag behaviour
+		 */
+		private function mouseMoveOnVisibleRectangleGroupEventHandler(event : MouseEvent) : void
+		{
+			if (event.buttonDown)
+			{
+				visibleRectangleGroup.startDrag(false, new Rectangle(0,0,this.width - rectangle.width, this.height - rectangle.height));
+				updateCanvasPosition();
+			}
+			else visibleRectangleGroup.stopDrag();
+		}
+
+		/**
+		 * Update the position of corresponding canvas based on visible rectangle
+		 */
+		private function updateCanvasPosition() : void
+		{
+			targetCanvas.surface.x = -visibleRectangleGroup.x * currentMaxWidth / this.width;
+			targetCanvas.surface.y = -visibleRectangleGroup.y * currentMaxHeight / this.height;			
+		}
+		
+		/**
+		 * Update position of visible rectangle on the minimap
+		 */
+		private function updateVisibleRectanglePosition() : void
+		{
+			visibleRectangleGroup.x = -targetCanvas.surface.x * this.width / currentMaxWidth;
+			visibleRectangleGroup.y = -targetCanvas.surface.y * this.height / currentMaxHeight;
+		}
+
+		/**
+		 * Update object position on the minimap
+		 */
+		public function UpdateObject(object : GenderObject, wasDeleted : Boolean = false) : void
+		{
+			var minimapObject : Group = null;
+			if (objects.hasOwnProperty(object.id))
+			{
+				minimapObject = objects[object.id];
+				if (wasDeleted)
+				{
+					this.removeChild(minimapObject);
+					minimapObject.graphics.clear();
+					objects[object.id] = null;
+				}
+				else
+				{
+					minimapObject.x = (object.x + object.width/2) / _scaleX;
+					minimapObject.y = (object.y + object.height/2) / _scaleY;
+				}
+			}
+			else
+			{
+				minimapObject = new Group();
+				objects[object.id] = minimapObject;
+				var circle : Ellipse = new Ellipse();
+				circle.x = -10;
+				circle.y = -10;
+				circle.width = 6;
+				circle.height = 6;
+				var _lineStroke : SolidColorStroke = new SolidColorStroke(ColorKeys.BLUE);
+	            if (object is ResourceObject) _lineStroke.color = ColorKeys.GREEN;
+	            if (object is UserObject) _lineStroke.color = ColorKeys.RED;
+	            _lineStroke.weight = 2;
+	            circle.stroke = _lineStroke;
+				minimapObject.addElement(circle);
+				minimapObject.x = (object.x + object.width/2) / _scaleX;
+				minimapObject.y = (object.y + object.height/2) / _scaleY;
+				this.addChild(minimapObject);
+			}
+		}
+		
+		/**
+		 * Handle canvas size change
+		 */
+		public function scaleChanged() : void
+		{
+			var matrix : Matrix = targetCanvas.surface.transform.matrix;
+			numberOfScreensHorizontal = (targetCanvas.maximumWidth * matrix.a) / targetCanvas.width;
+			numberOfScreensVertical = (targetCanvas.maximumHeight * matrix.d) / targetCanvas.height;
+			currentMaxWidth = targetCanvas.maximumWidth * matrix.a;
+			currentMaxHeight = targetCanvas.maximumHeight * matrix.d;
+			rectangle.width = this.width/numberOfScreensHorizontal;
+			rectangle.height = this.height/numberOfScreensVertical;
+		}
+		
+		/**
+		 * Clean minimap from all objects
+		 */
+		public function clean() : void
+		{
+			while (this.graphicsCollection.items.length) {
+				this.graphicsCollection.removeItemAt(0);
+			}
+			while (this.numChildren) {
+				this.removeChildAt(0);
+			}
+			objects = new Object();
+			this.addChild(visibleRectangleGroup);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/ComputingResource.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/ComputingResource.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/ComputingResource.as	(revision 15)
@@ -0,0 +1,77 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.resources.types.HostParameterType;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing computing resource
+	 */
+	public class ComputingResource extends Resource
+	{
+		/**
+		 * Node Info for queueing system
+		 */
+		[Bindable]
+		public var nodeInfo : NodeInfo
+		
+		/**
+		 * Collection of hostParameters included with this computing resource
+		 */
+		[Bindable]
+		public var hostParameters : ArrayCollection;
+		
+		/**
+		 * Collection of otherParameters included with this computing resource
+		 */
+		[Bindable]
+		public var otherParameters : ArrayCollection;
+		
+		[Bindable]
+		public var count : Number = 1;
+		
+		public function ComputingResource()
+		{
+			hostParameters = new ArrayCollection();
+			otherParameters = new ArrayCollection();
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <computingResource />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "resourceId", resourceId, true);
+			var xmlMachine : XML = <machineParameters />;
+			for each (var host : HostParameter in hostParameters)
+			{
+				xmlMachine.appendChild(host.getXML(addLabel));
+			}
+			for each (var other : OtherParameter in otherParameters)
+			{
+				xmlMachine.appendChild(other.getXML(addLabel));
+			}
+			xml.appendChild(xmlMachine);
+			if (nodeInfo != null) xml.appendChild(nodeInfo.getXML(addLabel));
+			
+			return xml;
+		}
+		
+		public override function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			/*
+			var ae : AbstractError;
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				if (preferenceType == null) ac.addItem(new PreferenceError("MissingPreferenceTypeError", this));
+				for each (ae in param.validate()) ac.addItem(ae);
+			}*/
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/file/resourcesWriter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/file/resourcesWriter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/file/resourcesWriter.as	(revision 15)
@@ -0,0 +1,73 @@
+package gssim.gssimstudio.editor.gssim.resources.file
+{
+	import flash.net.FileReference;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+	import gssim.gssimstudio.editor.gssim.resources.ComputingResource;
+	import gssim.gssimstudio.editor.gssim.resources.NodeInfo;
+	import gssim.gssimstudio.editor.gssim.resources.Resource;
+	import gssim.gssimstudio.editor.gssim.resources.ResourcesBasic;
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	import gssim.gssimstudio.editor.gssim.topology.ResourceObject;
+	
+	/**
+	 * Writes network topology to file
+	 */
+	public class resourcesWriter
+	{
+		private var fref : FileReference;
+		private var basic : ResourcesBasic;
+		
+		public function resourcesWriter()
+		{
+			basic = new ResourcesBasic();
+			for each (var node : GenderObject in ObjectCanvas.graph.nodes)
+			{
+				if (node is ResourceObject)
+				{
+					var res : ResourceObject = node as ResourceObject;
+					if (res.cluster)
+					{
+						basic.resources.addItem(res.frontend);
+						basic.queues.addItem(res.queue);
+						var info : NodeInfo = new NodeInfo();
+						info.frontendId = res.frontend.resourceId;
+						info.queueId = res.queue.resourceId;
+						for each (var clusteredRes : ComputingResource in res.clusteredResources)
+						{
+							clusteredRes.nodeInfo = info;
+							if (clusteredRes.count > 1)
+							{
+								for (var i : Number = 0; i < clusteredRes.count; i++)
+								{
+									var cRes : ComputingResource = new ComputingResource();
+									cRes.resourceId = clusteredRes.resourceId + "_" + i.toString();
+									cRes.hostParameters = clusteredRes.hostParameters;
+									cRes.otherParameters = clusteredRes.otherParameters;
+									cRes.nodeInfo = info;
+									basic.resources.addItem(cRes);
+								}
+							}
+							else
+								basic.resources.addItem(clusteredRes);
+						}
+					}
+					else
+						basic.resources.addItem(res.frontend);
+				}
+			}
+		}
+		
+		public function saveToFile() : void
+		{
+			//this doesnt work under IE
+			fref = new FileReference();
+			fref.save(getXMLString());
+		}
+		
+		public function getXMLString() : String
+		{
+			return basic.toXMLString();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/file/resourceReader.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/file/resourceReader.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/file/resourceReader.as	(revision 15)
@@ -0,0 +1,309 @@
+package gssim.gssimstudio.editor.gssim.resources.file
+{
+	import flash.events.Event;
+	import flash.net.FileReference;
+	import flash.utils.ByteArray;
+	import flash.utils.Dictionary;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+	import gssim.gssimstudio.editor.gssim.resources.ComputingResource;
+	import gssim.gssimstudio.editor.gssim.resources.HostParameter;
+	import gssim.gssimstudio.editor.gssim.resources.NodeInfo;
+	import gssim.gssimstudio.editor.gssim.resources.OtherParameter;
+	import gssim.gssimstudio.editor.gssim.resources.Property;
+	import gssim.gssimstudio.editor.gssim.resources.QueueParameter;
+	import gssim.gssimstudio.editor.gssim.resources.QueueResource;
+	import gssim.gssimstudio.editor.gssim.resources.ResourcesBasic;
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	import gssim.gssimstudio.editor.gssim.topology.GenderObjectFactory;
+	import gssim.gssimstudio.editor.gssim.topology.Graph;
+	import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+	import gssim.gssimstudio.editor.gssim.topology.ResourceObject;
+	import gssim.gssimstudio.editor.gssim.topology.RouterObject;
+	import gssim.gssimstudio.editor.gssim.topology.UserObject;
+	import gssim.gssimstudio.editor.gssim.topology.layouts.gssimFileLayout;
+	import gssim.gssimstudio.editor.gssim.topology.layouts.gssimRadialLayout;
+	
+	import mx.utils.StringUtil;
+	
+	import gssim.gssimstudio.editor.script.event.ObjectEvent;
+	import gssim.gssimstudio.editor.script.views.ViewsHelper;
+	
+	/**
+	 * Loads resources from file
+	 */
+	public class resourceReader
+	{
+		private var fref : FileReference;
+		private var _canvas : ObjectCanvas;
+		
+		public function resourceReader(canvas : ObjectCanvas, autobrowse : Boolean = true)
+		{
+			_canvas = canvas;
+			if (autobrowse)
+			{
+				fref = new FileReference();
+				fref.addEventListener(Event.SELECT, selectHandler);
+				fref.addEventListener(Event.COMPLETE, completeHandler);
+				fref.browse();
+			}
+		}
+		
+		public function selectHandler(event:Event):void
+		{
+		    fref.load();
+		}
+		
+		private function readProperty(xml : XML) : Property
+		{
+			var property : Property = new Property();
+			if (xml.attributes().length() == 1)
+			{
+				for each (var type : XML in xml.attributes())
+				{
+					if (type.name() == "name")
+						property.propertyType = type;
+				}
+			}
+			else
+				throw Error("Invalid file format");
+			
+			for each (var param : XML in xml.children())
+			{
+				if (param.name() == "value")
+				{
+					property.propertyValue = param;
+				}
+			}
+			return property;
+		}
+		
+		private function readHostParameter(xml : XML) : HostParameter
+		{
+			var host : HostParameter = new HostParameter();
+			if (xml.attributes().length() == 1)
+			{
+				for each (var type : XML in xml.attributes())
+				{
+					if (type.name() == "name")
+						host.hostParameterType = type;
+				}
+			}
+			else
+				throw Error("Invalid file format");
+			
+			for each (var param : XML in xml.children())
+			{
+				if (param.name() == "paramValue")
+				{
+					host.hostParameterParamValue = param;
+				}
+				if (param.name() == "property")
+				{
+					host.properties.addItem(readProperty(param));
+				}
+			}
+			return host;
+		}
+		
+		private function readOtherParameter(xml : XML) : OtherParameter
+		{
+			var other : OtherParameter = new OtherParameter();
+			if (xml.attributes().length() == 1)
+			{
+				for each (var type : XML in xml.attributes())
+				{
+					if (type.name() == "name")
+						other.otherParameterType = type;
+				}
+			}
+			else
+				throw Error("Invalid file format");
+			
+			for each (var param : XML in xml.children())
+			{
+				if (param.name() == "paramValue")
+				{
+					other.otherParameterValue = param;
+				}
+			}
+			return other;
+		}
+		
+		private function readQueueParameter(xml : XML) : QueueParameter
+		{
+			var queue : QueueParameter = new QueueParameter();
+			if (xml.attributes().length() == 1)
+			{
+				for each (var type : XML in xml.attributes())
+				{
+					if (type.name() == "name")
+						queue.queueParameterType = type;
+				}
+			}
+			else
+				throw Error("Invalid file format");
+			
+			for each (var param : XML in xml.children())
+			{
+				if (param.name() == "paramValue")
+				{
+					queue.queueParameterValue = param;
+				}
+			}
+			return queue;
+		}
+		
+		private function readComputingResource(xml : XML) : ComputingResource
+		{
+			var res : ComputingResource = new ComputingResource();
+			//read name
+			if (xml.attributes().length() == 1)
+			{
+				for each (var paramName : XML in xml.attributes())
+				{
+					if (paramName.name() == "resourceId")
+						res.resourceId = paramName;
+				}
+			}
+			//read host&other parameters
+			for each (var param : XML in xml.machineParameters.children())
+			{
+				if (param.name() == "hostParameter")
+				{
+					res.hostParameters.addItem(readHostParameter(param));
+				}
+				if (param.name() == "otherParameter")
+				{
+					res.otherParameters.addItem(readOtherParameter(param));
+				}
+			}
+			if (xml.hasOwnProperty("nodeInfo"))
+			{
+				var node : NodeInfo = new NodeInfo();
+				for each (var info : XML in xml.nodeInfo.children())
+				{
+					if (info.name() == "frontendResourceIdRef")
+					{
+						node.frontendId = info;
+					}
+					if (info.name() == "queueResourceIdRef")
+					{
+						node.queueId = info;
+					}
+				}
+				res.nodeInfo = node;
+			}
+			return res;
+		}
+		
+		private function readQueueResource(xml : XML) : QueueResource
+		{
+			var res : QueueResource = new QueueResource();
+			//read name
+			if (xml.attributes().length() == 1)
+			{
+				for each (var paramName : XML in xml.attributes())
+				{
+					if (paramName.name() == "resourceId")
+						res.resourceId = paramName;
+				}
+			}
+			//read queue parameters
+			for each (var param : XML in xml.queueParameters.children())
+			{
+				if (param.name() == "queueParameter")
+				{
+					res.queueParameters.addItem(readQueueParameter(param));
+				}
+			}
+			return res;
+		}
+		
+		public function completeHandler(event:Event):void
+		{
+			//var resources : ResourcesBasic = new ResourcesBasic();
+			var data:ByteArray = fref.data;
+			readFromString(data);
+			fref = null;
+		}
+		
+		public function readFromString(data:ByteArray):void
+		{
+			//var resources : ResourcesBasic = new ResourcesBasic();
+			var names : Object = new Object(); //map of name->count
+			var resources : Object = new Object(); //map of name->computing resource
+			var graph : Graph = ObjectCanvas.graph;
+			
+			var xml : XML;
+			xml = XML(data.readUTFBytes(data.bytesAvailable));
+			var xmlList : XMLList = xml.resources;
+			
+			var addedResource : Boolean = false;
+			
+			for each (var inner_computing_xml : XML in xml.resources.computingResource)
+			{
+				var computing : ComputingResource = readComputingResource(inner_computing_xml);
+				//resources.resources.addItem(computing);
+				if (computing.nodeInfo != null)
+				{
+					var name : String = computing.resourceId.split("_")[0];
+					if (!names.hasOwnProperty(name))
+					{
+						names[name] = 0;
+						resources[name] = computing;
+					}
+					names[name]++;
+				}
+				else
+				{
+					if (graph.hasNode(computing.resourceId))
+						(graph.nodes[computing.resourceId] as ResourceObject).frontend = computing;
+					else
+					{
+						addedResource = true;
+						var manualRes: ResourceObject = GenderObjectFactory.createResource(0,0,94,94);
+						manualRes.id = computing.resourceId;
+						_canvas.addGenderObject(manualRes);
+						(graph.nodes[computing.resourceId] as ResourceObject).frontend = computing;
+					}
+				}
+			}
+			
+			for (var n : String in names)
+			{
+				var res : ComputingResource = resources[n];
+				if (graph.hasNode(res.nodeInfo.frontendId))
+				{
+					(graph.nodes[res.nodeInfo.frontendId] as ResourceObject).clusteredResources.addItem(res);
+					res.count = names[n];
+				}
+			}
+			
+			for each (var inner_queue_xml : XML in xml.resources.queueResource)
+			{
+				var queue : QueueResource = readQueueResource(inner_queue_xml); 
+				//resources.queues.addItem(queue);
+				var resId : String = queue.resourceId.split("_")[0];
+				if (graph.hasNode(resId))
+				{
+					(graph.nodes[resId] as ResourceObject).queue = queue;
+					(graph.nodes[resId] as ResourceObject).convertToCluster();
+				}
+			}
+						
+			//apply layout if new resources were added
+			if (addedResource)
+			{
+				_canvas.forceStopDrag(null);
+				_canvas.applyLayout(new gssimFileLayout(_canvas.width));	
+			}
+			
+			//clear reference
+			_canvas = null;
+			
+			//resources.toXMLString();
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/HostParameter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/HostParameter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/HostParameter.as	(revision 15)
@@ -0,0 +1,67 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.resources.types.HostParameterType;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing resource host parameter
+	 */
+	public class HostParameter extends XMLBasicWrapper implements ValidableObject
+	{
+		/**
+		 * Type of the host parameter
+		 */
+		[Bindable]
+		public var hostParameterType : String;
+		
+		/**
+		 * Value of parameter
+		 */
+		[Bindable]
+		public var hostParameterParamValue : String;
+		
+		/**
+		 * Collection of properties included with this host parameter
+		 */
+		[Bindable]
+		public var properties : ArrayCollection;
+		
+		public function HostParameter()
+		{
+			hostParameterType = HostParameterType.cpucount;
+			properties = new ArrayCollection();
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <hostParameter />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "name", hostParameterType, true);
+			appendChildWithText(xml, "<paramValue/>", hostParameterParamValue, true, addLabel); 
+			for each (var param : Property in properties)
+			{
+				xml.appendChild(param.getXML(addLabel));
+			}
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			/*
+			var ae : AbstractError;
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				if (preferenceType == null) ac.addItem(new PreferenceError("MissingPreferenceTypeError", this));
+				for each (ae in param.validate()) ac.addItem(ae);
+			}*/
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/NodeInfo.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/NodeInfo.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/NodeInfo.as	(revision 15)
@@ -0,0 +1,55 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.resources.types.PropertyType;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing resource host parameter property
+	 */
+	public class NodeInfo extends XMLBasicWrapper implements ValidableObject
+	{
+		/**
+		 * Frontend ID
+		 */
+		[Bindable]
+		public var frontendId : String;
+
+		/**
+		 * Queue ID
+		 */
+		[Bindable]
+		public var queueId : String;
+				
+		public function NodeInfo()
+		{
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <nodeInfo />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			appendChildWithText(xml, "<frontendResourceIdRef/>", frontendId, true, addLabel);
+			appendChildWithText(xml, "<queueResourceIdRef/>", queueId, true, addLabel);
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			/*
+			var ae : AbstractError;
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				if (preferenceType == null) ac.addItem(new PreferenceError("MissingPreferenceTypeError", this));
+				for each (ae in param.validate()) ac.addItem(ae);
+			}*/
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/OtherParameter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/OtherParameter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/OtherParameter.as	(revision 15)
@@ -0,0 +1,57 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.resources.types.HostParameterType;
+	import gssim.gssimstudio.editor.gssim.resources.types.OtherParameterType;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing resource other parameter
+	 */
+	public class OtherParameter extends XMLBasicWrapper implements ValidableObject
+	{
+		/**
+		 * Type of the other parameter
+		 */
+		[Bindable]
+		public var otherParameterType : String;
+		
+		/**
+		 * Value of parameter
+		 */
+		[Bindable]
+		public var otherParameterValue : String;
+		
+		public function OtherParameter()
+		{
+			otherParameterType = OtherParameterType.energyprofile;
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <otherParameter />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "name", otherParameterType, true);
+			appendChildWithText(xml, "<paramValue/>", otherParameterValue, true, addLabel); 
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			/*
+			var ae : AbstractError;
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				if (preferenceType == null) ac.addItem(new PreferenceError("MissingPreferenceTypeError", this));
+				for each (ae in param.validate()) ac.addItem(ae);
+			}*/
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/HostParameterType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/HostParameterType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/HostParameterType.as	(revision 15)
@@ -0,0 +1,22 @@
+package gssim.gssimstudio.editor.gssim.resources.types
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * HostParameterType enum
+	 */
+	public final class HostParameterType
+	{
+		public static const cpucount : String = "cpucount";
+		public static const cpuspeed : String = "cpuspeed";
+		public static const memory : String = "memory";
+				public static function getAsArray() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			ac.addItem(cpucount);
+			ac.addItem(cpuspeed);
+			ac.addItem(memory);
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/OtherParameterType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/OtherParameterType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/OtherParameterType.as	(revision 15)
@@ -0,0 +1,20 @@
+package gssim.gssimstudio.editor.gssim.resources.types
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * OtherParameterType enum
+	 */
+	public final class OtherParameterType
+	{
+		public static const reservation : String = "reservation";
+		public static const energyprofile : String = "energyprofile";
+				public static function getAsArray() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			ac.addItem(reservation);
+			ac.addItem(energyprofile);
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/PropertyType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/PropertyType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/PropertyType.as	(revision 15)
@@ -0,0 +1,20 @@
+package gssim.gssimstudio.editor.gssim.resources.types
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * PropertyType enum
+	 */
+	public final class PropertyType
+	{
+		public static const corecount : String = "corecount";
+		public static const energyprofile : String = "energyprofile";
+				public static function getAsArray() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			ac.addItem(corecount);
+			ac.addItem(energyprofile);
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/QueueParameterType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/QueueParameterType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/types/QueueParameterType.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.editor.gssim.resources.types
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * QueueParameterType enum
+	 */
+	public final class QueueParameterType
+	{
+		public static const queueName : String = "queueName";
+		public static const priority : String = "priority";
+		
+		public static function getAsArray() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			ac.addItem(queueName);
+			ac.addItem(priority);
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/Property.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/Property.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/Property.as	(revision 15)
@@ -0,0 +1,56 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.resources.types.PropertyType;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing resource host parameter property
+	 */
+	public class Property extends XMLBasicWrapper implements ValidableObject
+	{
+		/**
+		 * Type of the property
+		 */
+		[Bindable]
+		public var propertyType : String;
+		
+		/**
+		 * Value of property
+		 */
+		[Bindable]
+		public var propertyValue : String;
+				
+		public function Property()
+		{
+			propertyType = PropertyType.corecount;
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <property />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "name", propertyType, true);
+			appendChildWithText(xml, "<value/>", propertyValue, true, addLabel);
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			/*
+			var ae : AbstractError;
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				if (preferenceType == null) ac.addItem(new PreferenceError("MissingPreferenceTypeError", this));
+				for each (ae in param.validate()) ac.addItem(ae);
+			}*/
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/QueueParameter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/QueueParameter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/QueueParameter.as	(revision 15)
@@ -0,0 +1,57 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.resources.types.HostParameterType;
+	import gssim.gssimstudio.editor.gssim.resources.types.QueueParameterType;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing resource queue parameter
+	 */
+	public class QueueParameter extends XMLBasicWrapper implements ValidableObject
+	{
+		/**
+		 * Type of the host parameter
+		 */
+		[Bindable]
+		public var queueParameterType : String;
+		
+		/**
+		 * Value of parameter
+		 */
+		[Bindable]
+		public var queueParameterValue : String;
+		
+		public function QueueParameter()
+		{
+			queueParameterType = QueueParameterType.queueName;
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <queueParameter />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "name", queueParameterType, true);
+			appendChildWithText(xml, "<paramValue/>", queueParameterValue, true, addLabel); 
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			/*
+			var ae : AbstractError;
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				if (preferenceType == null) ac.addItem(new PreferenceError("MissingPreferenceTypeError", this));
+				for each (ae in param.validate()) ac.addItem(ae);
+			}*/
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/Resource.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/Resource.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/Resource.as	(revision 15)
@@ -0,0 +1,43 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.resources.types.HostParameterType;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing computing resource
+	 */
+	public class Resource extends XMLBasicWrapper implements ValidableObject
+	{
+		/**
+		 * ID of the resource
+		 */
+		[Bindable]
+		public var resourceId : String;
+						
+		public function Resource()
+		{
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <resource />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "resourceId", resourceId, true);
+			
+			return xml;
+		}
+		
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/QueueResource.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/QueueResource.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/QueueResource.as	(revision 15)
@@ -0,0 +1,55 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.PreferenceError;
+	import gssim.gssimstudio.editor.gssim.workload.types.PreferenceType;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Class for storing QueueResource
+	 */
+	public class QueueResource extends Resource
+	{
+		/**
+		 * Collection of queueParameters included with this queue resource
+		 */
+		[Bindable]
+		public var queueParameters : ArrayCollection;
+		
+		public function QueueResource()
+		{
+			queueParameters = new ArrayCollection();
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <queueResource />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "resourceId", resourceId, true);
+			var xmlQueue : XML = <queueParameters />;
+			for each (var param : QueueParameter in queueParameters)
+			{
+				xmlQueue.appendChild(param.getXML(addLabel));
+			}
+			xml.appendChild(xmlQueue);
+			
+			return xml;
+		}
+		
+		public override function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			/*
+			var ae : AbstractError;
+			for each (var param : PreferenceParameter in preferenceParameters)
+			{
+				if (preferenceType == null) ac.addItem(new PreferenceError("MissingPreferenceTypeError", this));
+				for each (ae in param.validate()) ac.addItem(ae);
+			}*/
+			return ac;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/ResourcesBasic.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/ResourcesBasic.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/resources/ResourcesBasic.as	(revision 15)
@@ -0,0 +1,104 @@
+package gssim.gssimstudio.editor.gssim.resources
+{
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.errors.ValidableObject;
+	import gssim.gssimstudio.editor.gssim.errors.workload.ParametersError;
+	import gssim.gssimstudio.editor.gssim.errors.workload.RandParamsByTagError;
+	import gssim.gssimstudio.editor.gssim.xml.XMLBasicWrapper;
+	
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * Stores workload configuration properties
+	 */
+	public class ResourcesBasic extends XMLBasicWrapper implements ValidableObject
+	{
+		/**
+		 * Array collection with stored resources
+		 */
+		[Bindable]
+		public var resources : ArrayCollection;
+		
+		/**
+		 * Array collection with stored resources
+		 */
+		[Bindable]
+		public var queues : ArrayCollection;
+		
+		public function ResourcesBasic()
+		{
+			resources = new ArrayCollection();
+			queues = new ArrayCollection();
+		}
+		
+		public override function getXML(addLabel : Boolean) : XML
+		{
+			var xml : XML = <hostParameters />;
+			if (addLabel) addStringAttribute(xml, "label", xml.toXMLString(), false);
+			addStringAttribute(xml, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance", false);
+			
+			var xmlRes : XML = <resources />;
+			for each (var res2 : Resource in queues)
+			{
+				xmlRes.appendChild(res2.getXML(addLabel));
+			}
+			for each (var res : Resource in resources)
+			{
+				xmlRes.appendChild(res.getXML(addLabel));
+			}
+			xml.appendChild(xmlRes);
+			//for debug only
+			//trace(xml.toXMLString());
+			return xml;
+		}
+
+		public function validate() : ArrayCollection
+		{
+			var ac : ArrayCollection = new ArrayCollection();
+			var ae : AbstractError;
+			
+
+			/*
+			//check for reference id errors
+			var referencing : ArrayCollection = new ArrayCollection();
+			var listOfIds : ArrayCollection = new ArrayCollection();
+			for each (var rand : Object in properties)
+			{
+				if (rand is RandParams)
+				{
+					addToLists(listOfIds, referencing, rand as RandParams, ac);
+				}
+			}
+			for each (var cpar : ComputingResourceHostParameter in CRHP)
+			{
+				addToLists(listOfIds, referencing, cpar.value, ac);
+				addToLists(listOfIds, referencing, cpar.range.min, ac);
+				addToLists(listOfIds, referencing, cpar.range.max, ac);
+			}
+			for each (var r : RandParams in referencing)
+			{
+				if (!listOfIds.contains(r.params.RefElementId)) ac.addItem(new ParametersError("UnknownReferenceError", r.params));
+				else if (r.params.RefElementId == r.params.Id) ac.addItem(new ParametersError("SelfReferenceError", r.params));
+				//TODO: detect complex cycle references
+			}
+			*/
+			
+			return ac;
+		}
+		
+		/**
+		 * Add given id to lists for id reference errors validation
+		 */
+		/*
+		private function addToLists(ids : ArrayCollection, refs : ArrayCollection, rand : RandParams, errorList : ArrayCollection) : void
+		{
+			if (rand == null) return;
+			if (rand.params.Id != null && rand.params.Id != "")
+			{
+				if (ids.contains(rand.params.Id)) errorList.addItem(new ParametersError("DoubleIDError", rand.params));
+				else ids.addItem(rand.params.Id);
+			}
+			if (rand.params.RefElementId != null && rand.params.RefElementId != "") refs.addItem(rand);
+		}*/
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/PreferenceError.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/PreferenceError.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/PreferenceError.as	(revision 15)
@@ -0,0 +1,30 @@
+package gssim.gssimstudio.editor.gssim.errors.workload
+{
+	import gssim.gssimstudio.editor.gssim.editors.workload.PreferencesParameterWindow;
+	import gssim.gssimstudio.editor.gssim.editors.workload.PreferencesWindow;
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.workload.Preference;
+	
+	import gssim.gssimstudio.editor.script.views.ViewsHelper;
+
+	/**
+	 * Error raised if preference is invalid
+	 */
+	public class PreferenceError extends AbstractError
+	{
+		private var params : Preference;
+		
+		public function PreferenceError(message : String, params : Preference)
+		{
+			super(message);
+			this.params = params;
+		}
+		
+		public override function solve() : void
+		{
+			var window : PreferencesWindow = new PreferencesWindow();
+			ViewsHelper.WorkloadCanvas.windowManager.add(window);
+			window.setParams(params);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/PreferenceParameterError.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/PreferenceParameterError.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/PreferenceParameterError.as	(revision 15)
@@ -0,0 +1,29 @@
+package gssim.gssimstudio.editor.gssim.errors.workload
+{
+	import gssim.gssimstudio.editor.gssim.editors.workload.PreferencesParameterWindow;
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.workload.PreferenceParameter;
+	
+	import gssim.gssimstudio.editor.script.views.ViewsHelper;
+
+	/**
+	 * Error raised if preference parameter in preference is invalid
+	 */
+	public class PreferenceParameterError extends AbstractError
+	{
+		private var params : PreferenceParameter;
+		
+		public function PreferenceParameterError(message : String, params : PreferenceParameter)
+		{
+			super(message);
+			this.params = params;
+		}
+		
+		public override function solve() : void
+		{
+			var window : PreferencesParameterWindow = new PreferencesParameterWindow();
+			ViewsHelper.WorkloadCanvas.windowManager.add(window);
+			window.setParams(params);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/RandParamsByTagError.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/RandParamsByTagError.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/RandParamsByTagError.as	(revision 15)
@@ -0,0 +1,29 @@
+package gssim.gssimstudio.editor.gssim.errors.workload
+{
+	import gssim.gssimstudio.editor.gssim.editors.workload.RandParamsWindow;
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	
+	import gssim.gssimstudio.editor.script.views.ViewsHelper;
+
+	/**
+	 * Error rised if RandParams value defined by tag is invalid
+	 */
+	public class RandParamsByTagError extends AbstractError
+	{
+		private var paramName : String;
+		
+		public function RandParamsByTagError(messageCode : String, paramName : String)
+		{
+			super(messageCode);
+			this.message = paramName + ":";
+			this.paramName = paramName;
+		}
+		
+		public override function solve() : void
+		{
+			var window : RandParamsWindow = new RandParamsWindow();
+			window.init(paramName);
+			ViewsHelper.WorkloadCanvas.windowManager.add(window);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/ExistingRandParamsError.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/ExistingRandParamsError.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/ExistingRandParamsError.as	(revision 15)
@@ -0,0 +1,30 @@
+package gssim.gssimstudio.editor.gssim.errors.workload
+{
+	import gssim.gssimstudio.editor.gssim.editors.workload.RandParamsWindow;
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.workload.RandParams;
+	
+	import gssim.gssimstudio.editor.script.views.ViewsHelper;
+
+	/**
+	 * Error raised if referenceable RandParam value is invalid 
+	 */
+	public class ExistingRandParamsError extends AbstractError
+	{
+		private var params : RandParams;
+		
+		public function ExistingRandParamsError(messageCode : String, message : String, params : RandParams)
+		{
+			super(messageCode);
+			this.message = params.params.parentTagName + ": " + message;
+			this.params = params;
+		}
+		
+		public override function solve() : void
+		{
+			var window : RandParamsWindow = new RandParamsWindow();
+			window.params = params;
+			ViewsHelper.WorkloadCanvas.windowManager.add(window);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/ParametersError.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/ParametersError.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/workload/ParametersError.as	(revision 15)
@@ -0,0 +1,32 @@
+package gssim.gssimstudio.editor.gssim.errors.workload
+{
+	import gssim.gssimstudio.editor.gssim.editors.workload.ParameterAttributesWindow;
+	import gssim.gssimstudio.editor.gssim.editors.workload.RandParamsWindow;
+	import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+	import gssim.gssimstudio.editor.gssim.workload.ParameterAttributes;
+	import gssim.gssimstudio.editor.gssim.workload.RandParams;
+	
+	import gssim.gssimstudio.editor.script.views.ViewsHelper;
+
+	/**
+	 * Error raised if the probabilistic parameters are invalid
+	 */
+	public class ParametersError extends AbstractError
+	{
+		private var params : ParameterAttributes;
+		
+		public function ParametersError(messageCode : String, params : ParameterAttributes)
+		{
+			super(messageCode);
+			this.message = params.parentTagName + ":";
+			this.params = params;
+		}
+		
+		public override function solve() : void
+		{
+			var window : ParameterAttributesWindow = new ParameterAttributesWindow();
+			ViewsHelper.WorkloadCanvas.windowManager.add(window);
+			window.setParams(params);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/ValidableObject.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/ValidableObject.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/ValidableObject.as	(revision 15)
@@ -0,0 +1,15 @@
+package gssim.gssimstudio.editor.gssim.errors
+{
+	import mx.collections.ArrayCollection;
+	
+	/**
+	 * Interface for objects that are able to validate itself and return error list
+	 */
+	public interface ValidableObject
+	{
+		/**
+		 * This function should return ArrayCollection with list of errors.
+		 */
+		function validate() : ArrayCollection;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/AbstractError.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/AbstractError.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/errors/AbstractError.as	(revision 15)
@@ -0,0 +1,35 @@
+package gssim.gssimstudio.editor.gssim.errors
+{
+	import mx.resources.ResourceManager;
+	
+	/**
+	 * Abstract class for error handling
+	 */
+	public class AbstractError
+	{
+		private var messageCode : String;
+		protected var message : String;
+		
+		public function AbstractError(messageCode : String, message : String = "")
+		{
+			if (messageCode != null && messageCode != "")
+				this.messageCode = messageCode;
+			else
+				this.messageCode = "UnknownError";
+			this.message = message;
+		}
+
+		public function get Message() : String
+		{
+			return message + " " + ResourceManager.getInstance().getString('WorkloadEditor', messageCode);
+		}
+
+		/**
+		 * Solve the error
+		 */
+		public function solve() : void
+		{
+			//CAN'T SOLVE ABSTRACT ERROR
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GenderObject.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GenderObject.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GenderObject.as	(revision 15)
@@ -0,0 +1,108 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	import com.degrafa.core.utils.ColorKeys;
+	
+	import flash.events.Event;
+	
+	import mx.collections.ArrayCollection;
+	
+	import gssim.gssimstudio.editor.script.event.ObjectEvent;
+
+	public class GenderObject extends GraphItem
+	{
+		/***********************
+		 * Static embed images *
+		 ***********************/
+		[Embed(source="/gssim/gssimstudio/editor/assets/resource.png")] 
+		[Bindable] 
+		public static var ResourceImageCls:Class;
+		[Embed(source="/gssim/gssimstudio/editor/assets/router.png")] 
+		[Bindable] 
+		public static var RouterImageCls:Class;
+		[Embed(source="/gssim/gssimstudio/editor/assets/user.png")] 
+		[Bindable] 
+		public static var UserImageCls:Class;
+		[Embed(source="/gssim/gssimstudio/editor/assets/cluster.png")] 
+		[Bindable] 
+		public static var ClusterImageCls:Class;
+		
+		public var links : ArrayCollection;
+		
+		/**
+		 *  Dispatched when an object moves on canvas.
+		 *
+		 *  @eventType script.event.ObjectMouseEvent
+		 */
+		[Event(name="ObjectMoved", type="script.event.ObjectEvent")]
+		
+		public static const OBJECT_MOVED:String = "ObjectMoved";
+		
+		private var _selected : Boolean;
+		public function set selected(value : Boolean) :void { _selected = value; dispatchEvent(new Event("selected")); };
+		public function get selected() : Boolean { return _selected; };
+		
+		[Bindable(event="selected")]
+		public function get selectedColor() : uint
+		{
+			if (_selected)
+				return ColorKeys.GREEN;
+			return ColorKeys.BLACK;
+		}
+		
+		public function GenderObject(name : String, source : Class)
+		{
+			super(name);
+			this.source = source;
+			links = new ArrayCollection();
+		}
+		
+		public override function dispatchMoveAction() : void
+		{
+			for each (var link : NetworkObjectLinker in links)
+			{
+				link.refresh();
+			}
+			dispatchEvent(new ObjectEvent(OBJECT_MOVED, this));
+		}
+		
+		/**
+		 * Update all link names that connects to this object
+		 */
+		public function UpdateLinkNames() : void
+		{
+			for each (var k : NetworkObjectLinker in links)
+			{
+				k.UpdateID();
+			}
+		}
+		
+		/**
+		 * Clear all links
+		 */
+		public function clean() : void
+		{
+			for each (var k : NetworkObjectLinker in links)
+			{
+				if (k.NodeFrom != this) k.NodeFrom.removeLink(k);
+				else k.NodeTo.removeLink(k);
+				k.graphics.clear();
+			}
+		}
+		
+		/**
+		 * Remove certain link
+		 */
+		public function removeLink(link : NetworkObjectLinker) : void
+		{
+			links.removeItemAt(links.getItemIndex(link));
+		}
+		
+		/**
+		 * Returns true if this object can be linked with the object from argument
+		 */
+		public function canBeConnected(object : GenderObject) : Boolean
+		{
+			return true;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/file/topologyReader.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/file/topologyReader.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/file/topologyReader.as	(revision 15)
@@ -0,0 +1,283 @@
+package gssim.gssimstudio.editor.gssim.topology.file
+{
+	import flash.events.Event;
+	import flash.geom.Utils3D;
+	import flash.net.FileReference;
+	import flash.utils.ByteArray;
+	import flash.utils.Dictionary;
+	
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	import gssim.gssimstudio.editor.gssim.topology.GenderObjectFactory;
+	import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+	import gssim.gssimstudio.editor.gssim.topology.ResourceObject;
+	import gssim.gssimstudio.editor.gssim.topology.RouterObject;
+	import gssim.gssimstudio.editor.gssim.topology.UserObject;
+	import gssim.gssimstudio.editor.gssim.topology.layouts.gssimRadialLayout;
+	import gssim.gssimstudio.editor.script.event.ObjectEvent;
+	
+	import mx.controls.Alert;
+	import mx.core.ByteArrayAsset;
+	import mx.utils.ArrayUtil;
+	import mx.utils.StringUtil;
+	
+	/**
+	 * Loads network topology from file
+	 */
+	public class topologyReader
+	{
+		private var fref : FileReference;
+		private var _canvas : ObjectCanvas;
+		
+		public static const PHASE_ROUTERS:String = "routers";
+		public static const PHASE_ROUTERS_LINKS:String = "routers_links";
+    	public static const PHASE_RESOURCES_LINKS:String = "resources_links";
+    	public static const PHASE_USER_LINKS:String = "user_links";
+    	public static const PHASE_END:String = "eof";
+		
+		public function topologyReader(canvas : ObjectCanvas, autobrowse : Boolean = true)
+		{
+			_canvas = canvas;
+			if (autobrowse)
+			{
+				fref = new FileReference();
+				fref.addEventListener(Event.SELECT, selectHandler);
+				fref.addEventListener(Event.COMPLETE, completeHandler);
+				fref.browse();
+			}
+		}
+		
+		public function selectHandler(event:Event):void
+		{
+		    fref.load();
+		}
+			
+		public function readFromFile(file : FileReference) : void
+		{
+			fref = file;
+			completeHandler(null);
+		}
+		
+		public function readFromBinary(data : ByteArray) : void
+		{
+			var copy : ByteArray = new ByteArray();
+			copy.writeObject(data);
+			copy.position = 0;
+			copy = copy.readObject() as ByteArray;
+			var text : String = copy.readUTFBytes(copy.bytesAvailable);
+			var array : Array;
+			//will this be the same on unix ?
+			array = text.split('\r\n');
+			if (array.length == 1) array = text.split('\r');
+			if (array.length == 1) array = text.split('\n');
+			if (array.length == 1)
+			{
+				Alert.show("Inproper file format!");
+				return;
+			}
+			
+			readFromString(array);
+		}
+		
+		public function completeHandler(event:Event):void
+		{
+			if (_canvas == null)
+			{
+				Alert.show("Missing canvas!");
+				return;
+			}
+			
+			if (fref == null)
+			{
+				Alert.show("Missing file!");
+				return;
+			}
+			
+		    var data:ByteArray = fref.data;
+			
+			readFromBinary(data);
+			
+			fref = null;
+		}
+		
+		public function readFromString(array : Array) : void
+		{
+			_canvas.empty();
+			var count : int = -1;
+			var phase : String = PHASE_ROUTERS;
+			var usedNames : Dictionary = new Dictionary();
+			var splitted : Array;
+			var name1 : String;
+			var name2 : String;
+			var baudRate : Number;
+			var propDelay : Number;
+			var mtu : Number;
+			var nodeX : Number;
+			var nodeY : Number;
+	
+			//read file content into ObjectCanvas
+			for (var i : int = 0; i < array.length; i++)
+			{
+				if (array[i].charAt(0) == '#' || array[i] == "")
+					continue;
+				if (phase == PHASE_ROUTERS)
+				{ 
+					if (count == -1)
+						count = parseInt(array[i]);
+					else
+					if (count == 0)
+					{
+						phase = PHASE_ROUTERS_LINKS;
+						count = -1;
+					}
+					else
+					{
+						count--;
+						var router : RouterObject = GenderObjectFactory.createRouter(
+								0,
+								0,
+								94,
+								94);
+						router.nodeName = StringUtil.trim(array[i]);
+						router.id = router.nodeName;
+						_canvas.addGenderObject(router);
+					}
+				}
+				if (phase == PHASE_ROUTERS_LINKS)
+				{ 
+					if (count == -1)
+						count = parseInt(array[i]);
+					else
+					if (count == 0)
+					{
+						phase = PHASE_RESOURCES_LINKS;
+						count = -1;
+					}
+					else
+					{
+						count--;
+						splitted = array[i].replace(/\s+/g, ' ').split(' ');
+						name1 = splitted[0];
+						name2 = splitted[1];
+						baudRate = Number(splitted[2]);
+						propDelay = Number(splitted[3]);
+						mtu = Number(splitted[4]);
+						_canvas.linkObjectsById(name1, name2, baudRate, propDelay, mtu);
+					}
+				}
+				if (phase == PHASE_RESOURCES_LINKS)
+				{ 
+					if (count == -1)
+						count = parseInt(array[i]);
+					else
+					if (count == 0)
+					{
+						phase = PHASE_USER_LINKS;
+						count = -1;
+					}
+					else
+					{
+						count--;
+						splitted = array[i].replace(/\s+/g, ' ').split(' ');
+						name1 = splitted[0];
+						name2 = splitted[1];
+						if (!usedNames.hasOwnProperty(name1))
+						{
+							var resource : ResourceObject = GenderObjectFactory.createResource(
+									0,
+									0,
+									94,
+									94);
+							resource.nodeName = name1;
+							resource.id = resource.nodeName;
+							usedNames[name1] = "1";
+							_canvas.addGenderObject(resource);
+						}
+						baudRate = Number(splitted[2]);
+						propDelay = Number(splitted[3]);
+						mtu = Number(splitted[4]);
+						_canvas.linkObjectsById(name1, name2, baudRate, propDelay, mtu);
+					}
+				}
+				if (phase == PHASE_USER_LINKS)
+				{ 
+					if (count == -1)
+					{
+						count = parseInt(array[i]);
+						usedNames = new Dictionary();
+					}
+					else
+					if (count == 0)
+					{
+						phase = PHASE_END;
+						_canvas.forceStopDrag(null);
+						_canvas.applyLayout(new gssimRadialLayout());
+						count = -1;
+					}
+					else
+					{
+						count--;
+						splitted = array[i].replace(/\s+/g, ' ').split(' ');
+						name1 = splitted[0];
+						name2 = splitted[1];
+						if (!usedNames.hasOwnProperty(name1))
+						{
+							var user : UserObject = GenderObjectFactory.createUser(
+									0,
+									0,
+									94,
+									94);
+							user.nodeName = name1;
+							user.id = user.nodeName;
+							usedNames[name1] = "1";
+							_canvas.addGenderObject(user);
+						}
+						baudRate = Number(splitted[2]);
+						propDelay = Number(splitted[3]);
+						mtu = Number(splitted[4]);
+						_canvas.linkObjectsById(name1, name2, baudRate, propDelay, mtu);
+					}
+				}
+				if (phase == PHASE_END)
+				{ 
+					if (count == -1)
+					{
+						count = parseInt(array[i]);
+					}
+					else
+					if (count == 0)
+					{
+						phase = PHASE_END;
+						count = -1;
+					}
+					else
+					{
+						count--;
+						splitted = array[i].replace(/\s+/g, ' ').split(' ');
+						name1 = splitted[0];
+						nodeX = Number(splitted[1]);
+						nodeY = Number(splitted[2]);
+						var temp : GraphItem = ObjectCanvas.graph.find(name1);
+						if (temp != null)
+						{
+							temp.x = nodeX;
+							temp.y = nodeY;
+							temp.dispatchMoveAction();
+							_canvas.dispatchEvent(new ObjectEvent(ObjectCanvas.OBJECT_MOVED, temp as GenderObject));
+						}
+					}
+				}
+			}
+			if (count == 0 && phase == PHASE_USER_LINKS)
+			{
+				phase = PHASE_END;
+				_canvas.forceStopDrag(null);
+				_canvas.applyLayout(new gssimRadialLayout());
+				count = -1;
+			}
+			_canvas = null;
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/file/topologyWriter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/file/topologyWriter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/file/topologyWriter.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.editor.gssim.topology.file
+{
+	import flash.net.FileReference;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+	
+	/**
+	 * Writes network topology to file
+	 */
+	public class topologyWriter
+	{
+		private var fref : FileReference;
+		
+		public function topologyWriter()
+		{
+			//this doesnt work under IE
+			fref = new FileReference();
+			fref.save(ObjectCanvas.graph.toString());
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/ResourceObject.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/ResourceObject.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/ResourceObject.as	(revision 15)
@@ -0,0 +1,47 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	import gssim.gssimstudio.editor.gssim.resources.ComputingResource;
+	import gssim.gssimstudio.editor.gssim.resources.QueueResource;
+	
+	import mx.collections.ArrayCollection;
+
+	/**
+	 * Object representing Resource
+	 */
+	public class ResourceObject extends GenderObject
+	{
+		/**
+		 * Array of Resource
+		 */
+		public var clusteredResources : ArrayCollection;
+		
+		/**
+		 * Defines if this resource is a cluster of resources
+		 */
+		public var cluster : Boolean;
+		
+		public var queue : QueueResource;
+		public var frontend : ComputingResource;
+		
+		public function ResourceObject(name : String, cluster : Boolean = false)
+		{
+			super(name, (cluster ? ClusterImageCls : ResourceImageCls));
+			this.cluster = cluster;
+			clusteredResources = new ArrayCollection();
+		}
+		
+		public override function canBeConnected(object : GenderObject) : Boolean
+		{
+			if (links.length > 0) return false;
+			if (object is ResourceObject) return false;
+			if (object is UserObject) return false;
+			return true;
+		}
+		
+		public function convertToCluster() : void
+		{
+			this.source = ClusterImageCls;
+			this.cluster = true;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimSimpleLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimSimpleLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimSimpleLayout.as	(revision 15)
@@ -0,0 +1,60 @@
+package gssim.gssimstudio.editor.gssim.topology.layouts
+{
+	import gssim.gssimstudio.editor.gssim.topology.Graph;
+	import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+	import gssim.gssimstudio.editor.gssim.topology.UserObject;
+	
+	/**
+	 * Simple layout based on DFS algorithm
+	 */
+	public class gssimSimpleLayout implements ILayout
+	{
+		private var levels : Object; // map int -> int
+		
+		public function isStatic() : Boolean
+		{
+			return false;
+		}
+		
+		public function gssimSimpleLayout()
+		{
+			levels = new Object();
+		}
+
+		public function doLayout(graph:Graph):void
+		{
+			//graph is empty
+			if (!graph.hasNodes) return;
+			
+			//find user object, else take first item
+			//reset nodes
+			var id : String = graph.distinguishedGraphItem.id;
+			for each (var node : GraphItem in graph.nodes)
+			{
+				if (node is UserObject) id = node.id;
+				node.visited = false;
+			}
+			
+			layout(0, graph, graph.find(id));
+		}
+		
+		/**
+		 * Recursive function for setting positions of nodes
+		 */
+		private function layout(level : Number, graph : Graph, item : GraphItem) : void
+		{
+			if (!levels.hasOwnProperty(level)) levels[level] = 0;
+			else levels[level]++;
+			item.visited = true;
+			item.y = 96 * level;
+			item.x = 192 * levels[level];
+			item.dispatchMoveAction();
+			for (var id : String in graph.neighbors(item.id))
+			{
+				var node : GraphItem = graph.find(id); 
+				if (!node.visited) layout(level + 1, graph, node);
+			}
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimRadialLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimRadialLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimRadialLayout.as	(revision 15)
@@ -0,0 +1,58 @@
+package gssim.gssimstudio.editor.gssim.topology.layouts
+{
+	
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.layout.RadialTreeLayout;
+	
+	import gssim.gssimstudio.editor.gssim.topology.Graph;
+	import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+
+	/**
+	 * Radial layout imported from Flare
+	 */
+	public class gssimRadialLayout implements ILayout
+	{
+		public function gssimRadialLayout()
+		{
+			;
+		}
+		
+		public function isStatic() : Boolean
+		{
+			return false;
+		}
+
+		public function doLayout(graph:Graph) : void
+		{
+			if (!graph.hasNodes) return;
+			
+			var data : Data = new Data();
+			var nodes : Object = new Object();
+			for each (var item : GraphItem in graph.nodes)
+			{
+				var node : NodeSprite = data.addNode(item);
+				nodes[item.id] = node;
+			}
+			for each (var first : GraphItem in graph.nodes)
+			{
+				for (var neighbor : String in graph.neighbors(first.id))
+				{
+					data.addEdgeFor(nodes[first.id], nodes[neighbor]);
+				}
+			}
+			var radial : RadialTreeLayout = new RadialTreeLayout(150,true, false);
+			var vis : Visualization = new Visualization(data);
+			vis.operators.add(radial);
+			vis.update();
+			for (var i : Number = 0; i < data.nodes.length; i++)
+			{
+				var graphItem : GraphItem = data.nodes[i].data as GraphItem;
+				graphItem.x = data.nodes[i].x;
+				graphItem.y = data.nodes[i].y;
+				graphItem.dispatchMoveAction();		
+			}
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimFileLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimFileLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimFileLayout.as	(revision 15)
@@ -0,0 +1,48 @@
+package gssim.gssimstudio.editor.gssim.topology.layouts
+{
+	import gssim.gssimstudio.editor.gssim.topology.Graph;
+	import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+	
+	/**
+	 * Simple layout based on DFS algorithm
+	 */
+	public class gssimFileLayout implements ILayout
+	{	
+		public function isStatic() : Boolean
+		{
+			return false;
+		}
+		
+		protected var appWidth: Number = 0;
+		
+		public function gssimFileLayout(_width:Number)
+		{
+			appWidth = _width;
+		}
+
+		public function doLayout(graph:Graph):void
+		{
+			//graph is empty
+			if (!graph.hasNodes) return;
+			
+			//find user object, else take first item
+			//reset nodes
+			var x : Number = 0;
+			var y : Number = 0;
+			
+			for each (var node : GraphItem in graph.nodes)
+			{
+				node.x = x;
+				node.y = y;
+				x += 192;
+				if (x > appWidth - 191) 
+				{
+					x = 0;
+					y += 96;
+				}
+			}
+			
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimIndentLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimIndentLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimIndentLayout.as	(revision 15)
@@ -0,0 +1,58 @@
+package gssim.gssimstudio.editor.gssim.topology.layouts
+{
+	
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.layout.IndentedTreeLayout;
+	
+	import gssim.gssimstudio.editor.gssim.topology.Graph;
+	import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+
+	/**
+	 * Indent layout imported from Flare
+	 */
+	public class gssimIndentLayout implements ILayout
+	{
+		public function gssimIndentLayout()
+		{
+			;
+		}
+
+		public function isStatic() : Boolean
+		{
+			return false;
+		}
+
+		public function doLayout(graph:Graph) : void
+		{
+			if (!graph.hasNodes) return;
+			
+			var data : Data = new Data();
+			var nodes : Object = new Object();
+			for each (var item : GraphItem in graph.nodes)
+			{
+				var node : NodeSprite = data.addNode(item);
+				nodes[item.id] = node;
+			}
+			for each (var first : GraphItem in graph.nodes)
+			{
+				for (var neighbor : String in graph.neighbors(first.id))
+				{
+					data.addEdgeFor(nodes[first.id], nodes[neighbor]);
+				}
+			}
+			var indent : IndentedTreeLayout = new IndentedTreeLayout(100,40);
+			var vis : Visualization = new Visualization(data);
+			vis.operators.add(indent);
+			vis.update();
+			for (var i : Number = 0; i < data.nodes.length; i++)
+			{
+				var graphItem : GraphItem = data.nodes[i].data as GraphItem;
+				graphItem.x = data.nodes[i].x;
+				graphItem.y = data.nodes[i].y;
+				graphItem.dispatchMoveAction();		
+			}
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimForceDirectedLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimForceDirectedLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/gssimForceDirectedLayout.as	(revision 15)
@@ -0,0 +1,61 @@
+package gssim.gssimstudio.editor.gssim.topology.layouts
+{
+	
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.layout.ForceDirectedLayout;
+	
+	import gssim.gssimstudio.editor.gssim.topology.Graph;
+	import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+
+	/**
+	 * Force-directed layout imported from Flare
+	 */
+	public class gssimForceDirectedLayout implements ILayout
+	{
+		public function gssimForceDirectedLayout()
+		{
+			;
+		}
+		
+		public function isStatic() : Boolean
+		{
+			return true;
+		}
+
+		public function doLayout(graph:Graph) : void
+		{
+			var data : Data = new Data();
+			var nodes : Object = new Object();
+			for each (var item : GraphItem in graph.nodes)
+			{
+				var node : NodeSprite = data.addNode(item);
+				nodes[item.id] = node;
+				node.x = item.x;
+				node.y = item.y;
+			}
+			for each (var first : GraphItem in graph.nodes)
+			{
+				for (var neighbor : String in graph.neighbors(first.id))
+				{
+					data.addEdgeFor(nodes[first.id], nodes[neighbor]);
+				}
+			}
+			var force : ForceDirectedLayout = new ForceDirectedLayout(false, 200);
+			force.defaultSpringLength = 250;
+			force.defaultParticleMass = 10;
+			force.defaultSpringTension = 1;
+			var vis : Visualization = new Visualization(data);
+			vis.operators.add(force);
+			vis.update();
+			for (var i : Number = 0; i < data.nodes.length; i++)
+			{
+				var graphItem : GraphItem = data.nodes[i].data as GraphItem;
+				graphItem.x = data.nodes[i].x;
+				graphItem.y = data.nodes[i].y;
+				graphItem.dispatchMoveAction();		
+			}
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/ILayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/ILayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/layouts/ILayout.as	(revision 15)
@@ -0,0 +1,17 @@
+package gssim.gssimstudio.editor.gssim.topology.layouts
+{
+	import gssim.gssimstudio.editor.gssim.topology.Graph;
+	
+	/**
+	 * Interface for different layout implementations
+	 */
+	public interface ILayout
+	{
+		function doLayout(graph : Graph) : void;
+		/**
+		 * 	Defines if layout is made in-place of current layout
+		 * 
+		 */
+		function isStatic() : Boolean;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GraphItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GraphItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GraphItem.as	(revision 15)
@@ -0,0 +1,32 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	import com.degrafa.GraphicImage;
+	
+	/** The base class for all Graph items. Extends GraphicImage for graphic representation.
+	 */
+	public class GraphItem extends GraphicImage
+	{
+		/**
+		 * Variable used in DFS algorithms
+		 */
+		public var visited : Boolean;
+		
+		/**
+		 * Name of the node
+		 */
+		[Bindable]
+		public var nodeName : String;
+		
+		public function GraphItem(name : String)
+		{
+			nodeName = name;
+		}
+		
+		/**
+		 * Do some actions if the graph item was moved on canvas
+		 */
+		public function dispatchMoveAction() : void
+		{
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/Graph.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/Graph.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/Graph.as	(revision 15)
@@ -0,0 +1,436 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	
+	/**
+	 *  Dispatched when there is any change to the nodes and/or links of this graph.
+	 *
+	 *  @eventType flash.events.Event
+	 */
+	[Event(name="changed", type="flash.events.Event")]
+	
+	/**
+	 *  A Graph is a collection of items that can be linked to each other.
+	 */
+ 	public class Graph extends EventDispatcher
+	{
+		public static const CHANGE:String = "change";
+
+		public function Graph(): void {
+		}
+		
+		private var _nodes: Object = new Object(); // map of id -> GraphItem
+		private var _edges: Object = new Object(); // map of id -> (map of id -> 0)
+		private var nodeArray: Array/*of GraphItem*/; 
+		private var edgeArray: Array/*of [GraphItem, GraphItem]*/;
+		private var _distinguishedGraphItem: GraphItem;
+
+	    /**
+	     *  Removes an item from the graph.
+	     *
+	     *  @param item The item that you want to remove from the graph.
+	     */
+		public function remove(item:GraphItem):void
+		{
+			delete _nodes[item.id];
+			delete _edges[item.id];
+			
+			for (var id: String in _edges) {
+				var friends: Object = _edges[id];
+				delete friends[item.id];
+			}
+			
+			nodeArray = null;
+			edgeArray = null;
+			changed();
+		}
+		
+	    /**
+	     *  Remove the link between 2 items.
+	     *
+	     *  @param item1 an item in the graph that is linked to item2
+	     *  @param item2 an item in the graph that is linked to item1
+	     */
+		public function unlink(item1:GraphItem, item2:GraphItem):void
+		{
+			var friends: Object = _edges[item1.id];
+			delete friends[item2.id];
+			
+			friends = _edges[item2.id];
+			delete friends[item1.id];
+			
+			edgeArray = null;
+			changed();
+		}
+		
+	    /**
+	     *  An array of all the links in the graph.
+	     *  Each array element is an array of 2 strings, 
+	     *  which are the ids of two items that are linked.
+	     */
+		public function get edges():Array
+		{
+			if(edgeArray == null) {
+				edgeArray = new Array();
+				var done: Object = new Object();
+				for (var id: String in _edges) {
+					done[id] = true;
+					var friends: Object = _edges[id];
+					for (var friendID: String in friends) {
+						if(!done.hasOwnProperty(friendID))
+							edgeArray.push([_nodes[id], nodes[friendID]]);
+					}
+				}
+			}
+			return edgeArray;
+		}
+		
+	    /**
+	     *  An associative array of all the items in the graph.
+	     *  The key is the id, the value is the GraphItem.
+	     */
+		public function get nodes():Object
+		{
+			return _nodes;
+		}
+		
+	    /**
+	     *  True if this graph has any nodes at all.
+	     */
+		public function get hasNodes(): Boolean
+		{
+			for each (var item: GraphItem in _nodes) {
+				return true;
+			}
+			return false;
+		}
+		
+	    /**
+	     *  How many items are in this graph.
+	     */
+		public function get nodeCount(): int
+		{
+			var result:  int = 0;
+			for each (var item: GraphItem in _nodes) {
+				result++;
+			}
+			return result;
+		}
+		
+	    /**
+	     *  Link 2 items. This has no effect if the 2 items are already
+	     *  linked. Links are not directional: link(a,b) is equivalent to
+	     *  link(b,a).
+	     *
+	     *  @param item1 an item in the graph
+	     *  @param item2 an item in the graph
+	     *  @param data any data you like, or null. 
+	     */
+		public function link(item1:GraphItem, item2:GraphItem, data: Object = null):void
+		{
+			if(data == null) data = 0;
+			
+			var friends: Object = _edges[item1.id];
+			friends[item2.id] = data;
+			
+			friends = _edges[item2.id];
+			friends[item1.id] = data;
+			
+			edgeArray = null;
+			changed();
+		}
+	
+	    /**
+	     *  Add an item to the graph.
+	     *
+	     *  @param item an item to add to the graph
+	     */
+		public function add(item:GraphItem):void
+		{
+			if(_distinguishedGraphItem == null)
+				_distinguishedGraphItem = item;
+				
+			if(_nodes.hasOwnProperty(item.id)) {
+				return;
+			}
+			
+			_nodes[item.id] = item;
+			_edges[item.id] = new Object();
+			changed();
+		}
+		
+	    /**
+	     *  Find out if two items are linked.
+	     *
+	     *  @param item1 an item in the graph
+	     *  @param item2 an item in the graph
+	     *
+	     *  @return true if the two items are linked to each other.
+	     */
+		public function linked(item1:GraphItem, item2:GraphItem):Boolean
+		{
+			var friends: Object = _edges[item1.id];
+			return (friends != null) && friends.hasOwnProperty(item2.id);
+		}
+		
+	    /**
+	     *  retrieve the data that is associated with a link.
+	     *
+	     *  @param item1 an item in the graph
+	     *  @param item2 an item in the graph
+	     *
+	     *  @return Object the data that was associated with the link between the two items.
+	     *  If no data, or null, was associated with the link, we return 0. If there is no link
+	     *  between the items, we return null.
+	     */
+		public function getLinkData(item1:GraphItem, item2:GraphItem):Object
+		{
+			var friends: Object = _edges[item1.id];
+			
+			if ((friends != null) && friends.hasOwnProperty(item2.id))
+				return friends[item2.id];
+			else
+				return null;
+		}
+		
+	    /**
+	     *  Find out how many items are linked to a given item.
+	     *
+	     *  @param item an item in the graph
+	     *
+	     *  @return thes number of items to which this item is linked.
+	     */
+		public function numLinks(item: GraphItem): int {
+			var friends: Object = _edges[item.id];
+			var result: int = 0;
+			for (var i: String in friends) { 
+				result++; 
+			}
+			return result;
+		}
+		
+	    /**
+	     *  Find out if an item with a given id exists in the graph.
+	     *
+	     *  @param id any String
+	     *
+	     *  @return true if there is an item in the graph with the given id,
+	     *  false otherwise.
+	     */
+		public function hasNode(id: String): Boolean {
+			return _nodes.hasOwnProperty(id);
+		}
+		
+	    /**
+	     *  Find an item in the graph by id.
+	     *
+	     *  @param id any String
+	     *
+	     *  @return the item in the graph that has the given id,
+	     *  or null if there is no such item.
+	     */
+		public function find(id: String): GraphItem {
+			if(_nodes.hasOwnProperty(id))
+				return _nodes[id];
+			return null;
+		}
+		
+	    /**
+	     *  Get an array of all the items that a given item is linked to.
+	     *
+	     *  @param id any String
+	     *
+	     *  @return an array of GraphItems
+	     */
+		public function neighbors(id: String): Object {
+			return _edges[id];
+		}
+		
+	    /** Sometimes it's handy for the graph to remember one particular item.
+	     * You can use this for any purpose you like, it's not used internally by the Graph.
+	     * By default, the distinguished item is the first item that was added to this graph.
+	     */
+		public function get distinguishedGraphItem(): GraphItem {
+			return _distinguishedGraphItem;
+		}
+		
+		public function set distinguishedGraphItem(item: GraphItem): void {
+			_distinguishedGraphItem = item;
+		}
+		
+		/** Remove all items from the graph. */
+		public function empty(): void {
+			_nodes = new Object();
+			_edges = new Object();
+			nodeArray = null;
+			edgeArray = null;
+			_distinguishedGraphItem = null;
+			changed();	
+		}
+		
+		private function changed(): void {
+			dispatchEvent(new Event(CHANGE));
+		}
+		
+		/** Checks if graph is strongly connected. */
+		public function isStronglyConnected() : Boolean
+		{
+			if (!hasNodes) return false;
+			var id : String = distinguishedGraphItem.id;
+			for each (var node : GraphItem in nodes)
+			{
+				if (node is UserObject) id = node.id;
+				node.visited = false;
+			}
+			dfs(find(id));
+			for each (var node2 : GraphItem in nodes)
+			{
+				if (!node2.visited) return false;
+			}
+			return true;
+		}
+		
+		/** Depth-first-search */
+		private function dfs(item : GraphItem) : void
+		{
+			item.visited = true;
+			for (var id : String in neighbors(item.id))
+			{
+				var node : GraphItem = find(id); 
+				if (!node.visited) dfs(node);
+			}
+		}
+		
+		public override function toString():String
+		{
+			var result : String = "";
+			var countRouters : Number = 0;
+			var routers : Object = new Object(); //map id -> router
+			var countLinks : Number = 0;
+			var links : Object = new Object(); // map id -> link
+			var countLinksRes : Number = 0;
+			var links_res : Object = new Object(); // map id -> link
+			var countLinksUser : Number = 0;
+			var links_user : Object = new Object(); // map id -> link
+			for each (var node : GenderObject in _nodes)
+			{
+				if (node is RouterObject)
+				{
+					routers[node.id] = node;
+					countRouters++;
+				}
+				for each(var link : NetworkObjectLinker in node.links)
+				{
+					if (link.NodeFrom is RouterObject)
+					{
+						if (link.NodeTo is RouterObject)
+						{
+							if (!links.hasOwnProperty(link.id))
+							{
+								links[link.id] = link;
+								countLinks++;
+							}
+						}
+						else if (link.NodeTo is ResourceObject)
+						{
+							if (!links_res.hasOwnProperty(link.id))
+							{
+								links_res[link.id] = link;
+								countLinksRes++;
+							}
+						}
+						else if (link.NodeTo is UserObject)
+						{
+							if (!links_user.hasOwnProperty(link.id))
+							{
+								links_user[link.id] = link;
+								countLinksUser++;
+							}
+						}						
+					}
+					else if (link.NodeFrom is ResourceObject)
+					{
+						if (!links_res.hasOwnProperty(link.id))
+						{
+							links_res[link.id] = link;
+							countLinksRes++;
+						}
+					}
+					else if (link.NodeFrom is UserObject)
+					{
+						if (!links_user.hasOwnProperty(link.id))
+						{
+							links_user[link.id] = link;
+							countLinksUser++;
+						}
+					}	
+				}
+			}
+			//build final string
+			result += countRouters.toString() + "\r\n";
+			for each(var router : RouterObject in routers)
+			{
+				result += router.nodeName + "\r\n";
+			}
+			result += countLinks.toString() + "\r\n";
+			for each(var _link : NetworkObjectLinker in links)
+			{
+				result += _link.NodeFrom.nodeName + " " + _link.NodeTo.nodeName + " ";
+				result += _link.BaudRate.toString() + " ";
+				result += _link.PropDelay.toString() + " ";
+				result += _link.MTU.toString() + "\r\n";
+			}
+			result += countLinksRes.toString() + "\r\n";
+			for each(var _link_res : NetworkObjectLinker in links_res)
+			{
+				if (_link_res.NodeFrom is ResourceObject)
+					result += _link_res.NodeFrom.nodeName + " " + _link_res.NodeTo.nodeName + " ";
+				else
+					result += _link_res.NodeTo.nodeName + " " + _link_res.NodeFrom.nodeName + " ";
+				result += _link_res.BaudRate.toString() + " ";
+				result += _link_res.PropDelay.toString() + " ";
+				result += _link_res.MTU.toString() + "\r\n";
+			}
+			result += countLinksUser.toString() + "\r\n";
+			for each(var _link_user : NetworkObjectLinker in links_user)
+			{
+				if (_link_user.NodeFrom is UserObject)
+					result += _link_user.NodeFrom.nodeName + " " + _link_user.NodeTo.nodeName + " ";
+				else
+					result += _link_user.NodeTo.nodeName + " " + _link_user.NodeFrom.nodeName + " ";
+				result += _link_user.BaudRate.toString() + " ";
+				result += _link_user.PropDelay.toString() + " ";
+				result += _link_user.MTU.toString() + "\r\n";
+			}
+			result += nodeCount.toString() + "\r\n";
+			for each (var node2 : GenderObject in _nodes)
+			{
+				result += node2.nodeName + " ";
+				result += node2.x.toString() + " ";
+				result += node2.y.toString() + "\r\n";
+			}
+			links = null;
+			links_res = null;
+			links_user = null;
+			routers = null;
+			return result;
+		}
+		
+		 /**
+	     *  Translate whole graph by vector (tx, ty)
+	     *
+	     *  @param tx translate along X-axis
+	     *  @param ty translate along Y-axis
+	     */
+		public function translate(tx : Number, ty : Number) : void
+		{
+			for each (var node : GenderObject in _nodes)
+			{
+				node.x += tx;
+				node.y += ty;
+				node.dispatchMoveAction();
+			}
+		} 
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GenderObjectFactory.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GenderObjectFactory.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/GenderObjectFactory.as	(revision 15)
@@ -0,0 +1,52 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	/**
+	 * Factory for creating objects for network topology
+	 */
+	public class GenderObjectFactory
+	{
+		public static function createRouter(posX : int, posY : int, width : int, height: int) : RouterObject
+		{
+			var object : RouterObject = new RouterObject("null");
+				object.width = width;
+				object.height = height;
+				object.x = posX;
+				object.y = posY;
+				object.nodeName = object.id;
+			return object;
+		}
+
+		public static function createResource(posX : int, posY : int, width : int, height: int) : ResourceObject
+		{
+			var object : ResourceObject = new ResourceObject("null");
+				object.width = width;
+				object.height = height;
+				object.x = posX;
+				object.y = posY;
+				object.nodeName = object.id;
+			return object;
+		}
+		
+		public static function createUser(posX : int, posY : int, width : int, height: int) : UserObject
+		{
+			var object : UserObject = new UserObject("null");
+				object.width = width;
+				object.height = height;
+				object.x = posX;
+				object.y = posY;
+				object.nodeName = object.id;
+			return object;
+		}
+		
+		public static function createCluster(posX : int, posY : int, width : int, height: int) : ResourceObject
+		{
+			var object : ResourceObject = new ResourceObject("null", true);
+			object.width = width;
+			object.height = height;
+			object.x = posX;
+			object.y = posY;
+			object.nodeName = object.id;
+			return object;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/Linker.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/Linker.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/Linker.as	(revision 15)
@@ -0,0 +1,62 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	import com.degrafa.GeometryGroup;
+	import com.degrafa.geometry.Line;
+	import com.degrafa.paint.SolidStroke;
+	
+	/**
+	 * A standard link between two points
+	 */
+	public class Linker extends GeometryGroup
+	{
+		private var _x1 : Number;
+		private var _y1 : Number;
+		private var _x2 : Number;
+		private var _y2 : Number;
+		protected var line : Line;
+		public var geometryGroup : GeometryGroup;
+		
+		
+		public function get x1() : Number { return _x1; }
+		public function set x1(value : Number) : void { _x1 = value; }
+		public function get y1() : Number { return _y1; }
+		public function set y1(value : Number) : void { _y1 = value; }
+		public function get x2() : Number { return _x2; }
+		public function set x2(value : Number) : void { _x2 = value; }
+		public function get y2() : Number { return _y2; }
+		public function set y2(value : Number) : void { _y2 = value; }
+		
+		public function Linker(x1 : Number, y1 : Number, x2 : Number, y2: Number)
+		{
+			_x1 = x1;
+			_y1 = y1;
+			_x2 = x2;
+			_y2 = y2;
+			
+			line = new Line();
+			geometryGroup = new GeometryGroup();
+			
+			var _lineStroke : SolidStroke = new SolidStroke();
+            _lineStroke.color = "Gray";
+            _lineStroke.weight = 5;
+            line.stroke = _lineStroke;
+			
+			this.geometryCollection.addItem(line);
+			
+			refresh();
+		}
+		
+		/**
+		 * Redraw line
+		 */
+		public function refresh() : void
+		{
+			line.x = _x1;
+			line.y = _y1;
+			line.x1 = _x2;
+			line.y1 = _y2;
+			this.draw(null,null);
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/NetworkObjectLinker.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/NetworkObjectLinker.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/NetworkObjectLinker.as	(revision 15)
@@ -0,0 +1,114 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	import flash.events.Event;
+	import com.degrafa.paint.SolidStroke;
+	
+	/**
+	 * Linker between two GenderObjects in network topology
+	 */
+	public class NetworkObjectLinker extends Linker
+	{
+		private var nodeFrom : GenderObject;
+		public function get NodeFrom() : GenderObject { return nodeFrom; }
+		private var nodeTo : GenderObject;
+		public function get NodeTo() : GenderObject { return nodeTo; }
+		
+		private var _BaudRate : Number;
+		
+		public function get BaudRate() : Number { return _BaudRate; }
+		public function set BaudRate(value : Number) : void
+		{
+			_BaudRate = value;
+			UsedBaudRate = UsedBaudRate;
+		}
+		
+		public var PropDelay : Number;
+		
+		public var MTU : Number;
+		
+		private var _UsedBaudRate : Number;
+		
+		public function get UsedBaudRate() : Number { return _UsedBaudRate; }
+		public function set UsedBaudRate(value : Number) : void
+		{
+			if (isNaN(value)) _UsedBaudRate = 0;
+			else if (value == Number.NEGATIVE_INFINITY || value == Number.POSITIVE_INFINITY) _UsedBaudRate = 0;
+			else if (value > BaudRate) _UsedBaudRate = BaudRate;
+			else if (value < 0) _UsedBaudRate = 0;
+			else _UsedBaudRate = value;
+			updateLinkColor();
+		}
+		
+		[Event(name="Changed", type="flash.events.Event")]
+		
+		public static const CHANGE:String = "change";
+		
+		public function NetworkObjectLinker(nodeFrom : GenderObject, nodeTo : GenderObject, baudRate : Number = 0, propDelay : Number = 0, mtu : Number = 0)
+		{
+			this.nodeFrom = nodeFrom;
+			this.nodeTo = nodeTo;
+			
+			BaudRate = baudRate;
+			PropDelay = propDelay;
+			MTU = mtu;
+			
+			super(nodeFrom.x + nodeFrom.width/2,
+				nodeFrom.y + nodeFrom.height/2,
+				nodeTo.x + nodeTo.width/2,
+				nodeTo.y + nodeTo.height/2);
+				
+			UpdateID();
+		}
+		
+		/**
+		 * Update the link name based on the objects it connects
+		 */
+		public function UpdateID() : void
+		{
+			if (nodeFrom is RouterObject)
+			{
+				if (nodeTo is RouterObject)
+					this.id = nodeFrom.nodeName+"_"+nodeTo.nodeName+"_link";
+				else
+					this.id = nodeTo.nodeName+"_link";
+			} 
+			else
+				this.id = nodeFrom.nodeName+"_link";
+			dispatchEvent(new Event(CHANGE));
+		}
+		
+		/**
+		 * Change the link color based on the workload overload
+		 */
+		private function updateLinkColor() : void
+		{
+			//FIXME: this should be taken from RGB colors (not names) and from "gradient" like class
+			if (line == null) return;
+			var _lineStroke : SolidStroke = new SolidStroke();
+            _lineStroke.color = "Gray";
+            var percent : Number = 1- UsedBaudRate/BaudRate;
+            if (BaudRate == 0) null;
+            else if (percent < 0.2) _lineStroke.color = "Red";
+            else if (percent < 0.4) _lineStroke.color = "Orange";
+            else if (percent < 0.6) _lineStroke.color = "Yellow";
+            else if (percent < 0.8) _lineStroke.color = "LightGreen";
+            else _lineStroke.color = "Green";
+            _lineStroke.weight = 5;
+            line.stroke = _lineStroke;
+		}
+		
+		/**
+		 * Redraw line
+		 */
+		public override function refresh() : void
+		{
+			updateLinkColor();
+			line.x = nodeFrom.x + nodeFrom.width/2;
+			line.y = nodeFrom.y + nodeFrom.height/2;
+			line.x1 = nodeTo.x + nodeTo.width/2;
+			line.y1 = nodeTo.y + nodeTo.height/2;
+			this.draw(null,null);
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/UserObject.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/UserObject.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/UserObject.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	/**
+	 * Object representing User
+	 */
+	public class UserObject extends GenderObject
+	{		
+		public function UserObject(name : String)
+		{
+			super(name, UserImageCls);
+		}
+		
+		public override function canBeConnected(object : GenderObject) : Boolean
+		{
+			if (links.length > 0) return false;
+			if (object is ResourceObject) return false;
+			if (object is UserObject) return false;
+			return true;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/RouterObject.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/RouterObject.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/gssim/topology/RouterObject.as	(revision 15)
@@ -0,0 +1,13 @@
+package gssim.gssimstudio.editor.gssim.topology
+{
+	/**
+	 * Object representing Router
+	 */
+	public class RouterObject extends GenderObject
+	{		
+		public function RouterObject(name : String)
+		{
+			super(name, RouterImageCls);
+		}		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ExperimentComparisonChartModel.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ExperimentComparisonChartModel.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ExperimentComparisonChartModel.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.charts
+{
+import flash.events.EventDispatcher;
+import flash.utils.ByteArray;
+
+import mx.collections.ArrayCollection;
+
+	[Bindable]
+	[RemoteClass(alias = "gssim.gssimstudio.flex.app.editor.ExperimentComparisonChartModel")]
+	public class ExperimentComparisonChartModel {
+
+		public function ExperimentComparisonChartModel() {
+		}
+
+		public var error:String;
+
+		public var dataList:ArrayCollection;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ResourceChart.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ResourceChart.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ResourceChart.mxml	(revision 15)
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Canvas
+	xmlns:s="library://ns.adobe.com/flex/spark"
+	xmlns:mx="library://ns.adobe.com/flex/mx"
+	xmlns:cp="gssim.gssimstudio.editor.charts.com.connectedpixel.charts.*" 
+	xmlns:c="gssim.gssimstudio.editor.charts.components.*"
+	xmlns:fx="http://ns.adobe.com/mxml/2009"  
+	width="100%" creationComplete="init()"
+	height="100%" xmlns:charts="com.iwobanas.charts.*" xmlns:data="gssim.gssimstudio.editor.charting.data.*" xmlns:charts1="gssim.gssimstudio.editor.charts.*" 
+>
+	
+	<fx:Metadata>
+		[ResourceBundle("Charts")]
+	</fx:Metadata>
+	
+	<!--<charts1:ResourceChartModel id="model"/>-->
+	<fx:Script>
+	    <![CDATA[
+			import gssim.gssimstudio.editor.script.command.SaveToPNGCommand;
+			import gssim.gssimstudio.editor.script.views.ViewsHelper;
+			
+			import mx.binding.utils.BindingUtils;
+			import mx.charts.AxisRenderer;
+			import mx.charts.chartClasses.AxisLabelSet;
+			import mx.collections.ArrayCollection;
+			import mx.controls.Alert;
+			import mx.controls.HScrollBar;
+			import mx.controls.Label;
+			import mx.controls.scrollClasses.ScrollBar;
+			import mx.events.FlexEvent;
+			import mx.events.ResizeEvent;
+			import mx.events.ScrollEvent;
+			import mx.events.SliderEvent;
+			import mx.messaging.management.ObjectInstance;
+			import mx.rpc.events.ResultEvent;
+			import mx.utils.ArrayUtil;
+			import mx.utils.ObjectUtil;
+	
+			[Bindable]
+			public var expId : int;
+			[Bindable]
+			public var expName : String;
+			
+			[Bindable]
+			protected var date : Date = new Date();
+
+			private function formatDate(value:Date, previousValue:Date, axis:DateTimeAxis) : String 
+			{      
+				var percent : Number = 1;//_hZoom / 100;
+				var limit : Number = (hAxis.maximum.getTime() - hAxis.minimum.getTime()) * 0.07;
+				
+				if (hAxis.maximum.getTime() - value.getTime() > limit)
+				{
+					var dateLabel : String = df.format(value);
+					var dateLabelLongSec : String = dateLabel;
+					if (value.seconds < 10)
+					{
+						dateLabelLongSec = dateLabel.substring(0, dateLabel.length - 1);
+						dateLabelLongSec += "0" + value.seconds;
+					}
+					return dateLabelLongSec;
+				}
+				else
+				{
+					return "";
+				}
+			}
+			
+			private function saveAsPNG() : void
+			{
+				date = new Date();
+				var k : SaveToPNGCommand = new SaveToPNGCommand(fullChart);
+				k.execute();
+			}
+			
+			private function initChart(event : ResultEvent) : void
+			{
+				switch(chartTypeComboBox.selectedItem.type)
+				{
+					case "energy":
+						service.getResourceEnTimelineFromDb(resourceComboBox.selectedItem.PK, expId, null,null)
+						break;
+					case "allocation":
+						service.getResourceAllTimelineFromDb(resourceComboBox.selectedItem.PK, expId, null,null)
+						break;
+					default:
+						service.getResourceAllTimelineFromDb(resourceComboBox.selectedItem.PK, expId, null,null)
+						break;
+				}
+			}
+			
+			private function configurationLoaded(event : ResultEvent) : void
+			{
+				//dispatchEvent(new Event("configurationLoaded"));
+			}
+			
+			protected function init():void
+			{
+				parentApplication.addModelUpdatedSingleCallbacks(service.getResourcesFromDb(expId,null,null), initChart);
+				parentApplication.addModelUpdatedSingleCallbacks(service.getExperimentConfiguration(expId), configurationLoaded);
+			}
+			
+			private function onServerComboChange(ev:Event):void{
+				var selectedIndex :Number= resourceComboBox.selectedIndex;
+				switch(chartTypeComboBox.selectedItem.type)
+				{
+					case "energy":
+						service.getResourceEnTimelineFromDb(resourceComboBox.selectedItem.PK,expId,null,null)
+						break;
+					case "allocation":
+						service.getResourceAllTimelineFromDb(resourceComboBox.selectedItem.PK,expId,null,null)
+						break;
+					default:
+						service.getResourceAllTimelineFromDb(resourceComboBox.selectedItem.PK,expId,null,null)
+						break;
+				}
+				service.setSelectedResourceIndex(selectedIndex);
+			}
+
+			private function cloneChart() : void
+			{
+				var static : StaticResourceChart = new StaticResourceChart();
+				static.expName = expName;
+				static.resName = resourceComboBox.selectedItem.name;
+				static.dataProvider = ObjectUtil.copy(resourceViewer.dataProvider) as ArrayCollection;
+				ViewsHelper.ArchiveCanvas.windowManager.add(static);
+			}
+			
+			private function resourceLabelFunction(item : Object) : String
+			{
+				if (item.name == "(...)") return resourceManager.getString('Charts', 'Aggregate');
+				return item.name;
+			}
+			
+	    ]]>
+	</fx:Script>
+	
+	<fx:Style source="/gssim/gssimstudio/editor/assets/css/charts.css"/>
+
+	<fx:Declarations>
+	
+		<fx:Object id="service"/>
+		
+		<s:ArrayCollection id="chartTypeAC">
+			<fx:Object label="{resourceManager.getString('Charts', 'AllocationType')}" type="allocation"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'EnergyType')}" type="energy"/>
+		</s:ArrayCollection>
+		
+		<mx:SolidColorStroke id="s2" color="red" weight="2"/>
+		<mx:SolidColorStroke id="axisStroke" 
+			color="#224488" 
+			weight="8" 
+			alpha=".25"
+			caps="square"
+		/>
+		
+		<mx:SolidColor id="sc3" color="blue" alpha=".6"/>
+		
+		<mx:DateFormatter id="df" formatString="EEE, J:NN:S"/>
+		
+		<charts:ChartScroller chart="{resourceViewer}" chartMouseEnabled="true" verticalScrollEnabled="true" verticalZoomEnabled="true" />
+	
+	</fx:Declarations>
+		
+	<mx:VBox width="100%" height="100%">
+		<mx:HBox>
+			<mx:ComboBox dataProvider="{parentApplication.gsSimStudioModel.resourceChartComponents['' + expId].resourceList}" labelFunction="resourceLabelFunction" id="resourceComboBox"
+						 change="onServerComboChange(event)" selectedIndex="{parentApplication.gsSimStudioModel.resourceChartComponents['' + expId].selectedResourceIndex}" />
+			<mx:ComboBox dataProvider="{chartTypeAC}" id="chartTypeComboBox" change="onServerComboChange(event)"/>
+			<mx:Button label="{resourceManager.getString('Charts', 'Clone')}" click="cloneChart()"/>
+			<mx:Button label="PNG" click="saveAsPNG();"/>
+		</mx:HBox>
+		<mx:VBox width="100%" height="100%" verticalGap="1" id="fullChart">
+			<mx:Label text="{resourceManager.getString('Charts', 'ResourceAllocationTitle')}" width="100%" styleName="title"
+					  includeInLayout="{chartTypeComboBox.selectedItem.type == 'allocation'}"
+					  visible="{chartTypeComboBox.selectedItem.type == 'allocation'}"/>
+			<mx:Label text="{resourceManager.getString('Charts', 'ResourceEnergyTitle')}" width="100%" styleName="title"
+					  includeInLayout="{chartTypeComboBox.selectedItem.type == 'energy'}"
+					  visible="{chartTypeComboBox.selectedItem.type == 'energy'}"/>
+			<mx:Label text="{resourceManager.getString('Charts', 'CreatedFor')} {expName} {resourceManager.getString('Charts', 'Day')} {date}" width="100%" styleName="subtitle"/>
+			<mx:HBox width="100%" height="100%">
+				<mx:VBox width="100%" height="100%">
+				
+					<!--~~~~~~~~~~ RESOURCE VIEWER ~~~~~~~~~~-->
+					<mx:AreaChart 
+						id="resourceViewer" height="100%" width="100%"
+				        paddingRight="5" paddingLeft="5"
+						dataProvider="{parentApplication.gsSimStudioModel.resourceChartComponents['' + expId].resourceTimelineList}"
+				    >
+				        <mx:horizontalAxis>
+				            <mx:DateTimeAxis 
+				            	id="hAxis" 
+				            	dataUnits="seconds" 
+				            	alignLabelsToUnits="false" 
+				            	labelFunction="formatDate" 
+				            	title="{resourceManager.getString('Charts', 'SimulationTime')}"
+				             />
+				        </mx:horizontalAxis>
+				
+				        <mx:verticalAxis>
+				            <mx:LinearAxis 
+				            	id="vAxis" 
+				            	baseAtZero="false" 
+				            	maximumLabelPrecision="1" 
+				            	autoAdjust="false" 
+				            	title="{resourceManager.getString('Charts', 'CPU')}"
+				            />
+				        </mx:verticalAxis>
+				
+						<mx:series>
+				            <mx:AreaSeries 
+								filterData="false"
+				            	yField="usage" 
+				            	xField="timestamp" 
+				            	form="step" 
+				            	areaFill="{sc3}" 
+				            />
+				        </mx:series>
+					     
+				    </mx:AreaChart>
+				    <!--~~~~~~~~~~ END OF RESOURCE VIEWER ~~~~~~~~~~-->
+				    
+				</mx:VBox>
+			</mx:HBox>
+		</mx:VBox>
+	</mx:VBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/VExtendedSlider.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/VExtendedSlider.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/VExtendedSlider.mxml	(revision 15)
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
+	<mx:Style source="/gssim/gssimstudio/editor/assets/css/extendedSlider.css"/>
+	<mx:Script>
+		<![CDATA[
+			import mx.events.SliderEvent;
+			[Bindable]
+			public var minimum : Number = 0;
+			[Bindable]
+			public var maximum : Number = 100;
+			[Bindable]
+			private var _snapInterval : Number;
+			[Bindable]
+			public var value : Number = 50;
+			[Bindable]
+			public var liveDragging : Boolean = false;
+			
+			private var step : Number = 0.5;
+			
+			public function set change(value : Function) : void
+			{
+				vSlider.addEventListener(SliderEvent.CHANGE, value);
+			}
+			
+			public function set snapInterval(value : Number) : void
+			{
+				_snapInterval = value;
+				if (value > 0)
+					step = value;
+			}
+			
+			public function get snapInterval() : Number
+			{
+				return _snapInterval;
+			}
+		]]>
+	</mx:Script>
+	<mx:Button 
+		id="b1"
+		label="+" 
+		width="{20}" 
+		height="{20}"
+		styleName="zoomButton"
+		x="28" 
+		click="vSlider.value += step; vSlider.dispatchEvent(new SliderEvent(SliderEvent.CHANGE, false, false, -1, vSlider.value))"
+	/>
+	<mx:VSlider 
+		id="vSlider" 
+		height="{ this.height - b1.height - b2.height }" 
+		labels="['0','100']" 
+		labelStyleName="sliderLabel"
+		y="20" 
+		maximum="{ maximum }" 
+		minimum="{ minimum }" 
+		value="{ value }"
+		snapInterval="{ _snapInterval }"
+		liveDragging="{ liveDragging }"
+	/>
+	<mx:Button id="b2"
+		label="-" 
+		width="{20}" 
+		height="{20}"
+		styleName="zoomButton"
+		y="{ b1.height + vSlider.height }"
+		x="28"
+		click="vSlider.value -= step; vSlider.dispatchEvent(new SliderEvent(SliderEvent.CHANGE, false, false, -1, vSlider.value))"
+	/>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/HExtendedSlider.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/HExtendedSlider.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/HExtendedSlider.mxml	(revision 15)
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
+	<mx:Style source="/gssim/gssimstudio/editor/assets/css/extendedSlider.css"/>
+	<mx:Script>
+		<![CDATA[
+			import mx.events.SliderEvent;
+			[Bindable]
+			public var minimum : Number = 0;
+			[Bindable]
+			public var maximum : Number = 100;
+			[Bindable]
+			private var _snapInterval : Number;
+			[Bindable]
+			public var value : Number = 0;
+			[Bindable]
+			public var liveDragging : Boolean = false;
+			
+			private var step : Number = 0.5;
+			
+			private function init() : void
+			{
+				b1.y = 10 + Math.abs(parseInt(hSlider.getStyle('labelOffset')));
+				b2.y = 10 + Math.abs(parseInt(hSlider.getStyle('labelOffset')));
+			}
+			
+			public function set change(value : Function) : void
+			{
+				hSlider.addEventListener(SliderEvent.CHANGE, value);
+			}
+			
+			public function set snapInterval(value : Number) : void
+			{
+				_snapInterval = value;
+				if (value > 0)
+					step = value;
+			}
+			
+			public function get snapInterval() : Number
+			{
+				return _snapInterval;
+			}
+		]]>
+	</mx:Script>
+	<mx:Button 
+		id="b1"
+		label="-" 
+		width="{20}" 
+		height="{20}"
+		styleName="zoomButton"
+		click="{hSlider.value -= step; hSlider.dispatchEvent(new SliderEvent(SliderEvent.CHANGE, false, false, -1, hSlider.value))}"
+	/>
+	<mx:HSlider 
+		id="hSlider" 
+		width="{ this.width - b1.width - b2.width}" 
+		labels="['0','100']" 
+		x="20" 
+		labelStyleName="sliderLabel" 
+		minimum="{ minimum }" 
+		maximum="{ maximum }" 
+		value="{ value }"
+		snapInterval="{ _snapInterval }"
+		liveDragging="{ liveDragging }"
+	/>
+	<mx:Button id="b2"
+		label="+" 
+		width="{20}" 
+		height="{20}"
+		styleName="zoomButton"
+		y="10"
+		x="{ b1.width + hSlider.width }"
+		click="{hSlider.value += step; hSlider.dispatchEvent(new SliderEvent(SliderEvent.CHANGE, false, false, -1, hSlider.value))}"
+	/>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/Procline.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/Procline.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/components/Procline.mxml	(revision 15)
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
+	<mx:Script>
+		<![CDATA[
+			import mx.collections.ArrayCollection;
+			import mx.containers.VBox;
+			import mx.controls.Text;
+			
+			private var _dataProvider : ArrayCollection;
+			
+			[Bindable]
+			private var _rowHeight : int = 20;
+			
+			public var fontSize : int = 10;
+			
+			public function get yPosition() : Number
+			{
+				return container.verticalScrollPosition;
+			}
+			
+			public function set yPosition(value : Number) : void
+			{
+				if (container.verticalScrollPosition != value)
+				{
+					container.verticalScrollPosition = value;
+				}
+			}
+			
+			public function set dataProvider(value : ArrayCollection) : void
+			{
+				_dataProvider = value;
+				
+				if (value != null)
+				{				
+					container.removeAllChildren();
+					
+					for (var i : int = 0; i < value.length; ++i)
+					{
+						//var canvas : Canvas = new Canvas();
+						//canvas.setStyle("borderStyle", "none");
+						
+						var cell : Text = new Text();
+						cell.width = container.width - 2 * parseInt(container.getStyle("borderThickness"));
+						cell.height = rowHeight;
+						cell.text = value[i].toString();
+						cell.setStyle("fontSize", fontSize);
+						//trace(cell.height.toString() + " - " + fontSize.toString() + " / 2 = " + ((cell.height - fontSize) / 2).toString());
+						cell.setStyle("paddingTop", (cell.height - fontSize - 2) / 2);
+						cell.setStyle("textAlign", "left");
+						
+						//canvas.addChild(cell);
+						container.addChild(cell);
+					}
+				}
+			}
+			
+			public function get dataProvider() : ArrayCollection
+			{
+				return _dataProvider;
+			}
+			
+			public function get rowHeight() : int
+			{
+				return _rowHeight;
+			}
+			
+			public function set rowHeight(value : int) : void
+			{
+				if (value != _rowHeight)
+				{
+					_rowHeight = value;
+					for (var i : int = 0; i < _dataProvider.length; ++i)
+					{
+						var cell : Text = container.getChildAt(i) as Text;
+						cell.height = _rowHeight;
+						cell.setStyle("paddingTop", (cell.height - fontSize - 2) / 2);
+					}
+				}
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox 
+		id="container" 
+		width="{ this.width }" 
+		height="{ this.height }" 
+		borderStyle="none" 
+		horizontalScrollPolicy="off" 
+		verticalGap="0" 
+		scroll="dispatchEvent(event)"/>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/util/DateUtil.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/util/DateUtil.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/util/DateUtil.as	(revision 15)
@@ -0,0 +1,76 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.util
+{
+	public class DateUtil
+	{
+		public static const MINUTE_IN_MILLISECONDS : Number = 60 * 1000;
+		public static const HOUR_IN_MILLISECONDS : Number = 60 * 60 * 1000;
+		public static const DAY_IN_MILLISECONDS : Number = 24 * 60 * 60 * 1000;
+		public static const WEEK_IN_MILLISECONDS : Number = 7 * 24 * 60 * 60 * 1000;
+		public static const MONTH_IN_MILLISECONDS : Number = 30 * 24 * 60 * 60 * 1000;
+		public static const YEAR_IN_MILLISECONDS : Number = 12 * 30 * 24 * 60 * 60 * 1000;
+		public static const CENTURY_IN_MILLISECONDS : Number = 100 * 12 * 30 * 24 * 60 * 60 * 1000;
+		public static const MILLENIUM_IN_MILLISECONDS : Number = 1000 * 100 * 12 * 30 * 24 * 60 * 60 * 1000;
+		
+		public static function clearTime( date : Date ) : Date 
+		{	
+			date.hours = 0;
+			date.minutes = 0;
+			date.seconds = 0;
+			date.milliseconds = 0;
+			
+			return date;
+		}
+		
+		public static function copyDate( date : Date ) : Date 
+		{
+			return new Date( date.getTime() );
+		}
+		
+		public static function setTime( date : Date, time : Number ) : Date
+		{
+			date.hours = Math.floor(( time / (1000 * 60 * 60)) % 24);
+			date.minutes = Math.floor(( time / (1000 * 60)) % 60);
+			date.seconds = Math.floor(( time / 1000) % 60);
+			date.milliseconds = Math.floor( time % 1000); 
+			
+			return date;
+		}
+		
+		public static function addTime( date : Date, time : Number ) : Date 
+		{
+			date.milliseconds += time;
+			
+			return date;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/ScheduleViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/ScheduleViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/ScheduleViewer.as	(revision 15)
@@ -0,0 +1,782 @@
+/*
+
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+   @ignore
+ */
+package gssim.gssimstudio.editor.charts.scheduling
+{
+  import flash.events.Event;
+  import flash.events.MouseEvent;
+  
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.LayoutScrollEvent;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.Schedule;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.ScheduleNavigator;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IEntryLayout;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.schedule_internal;
+  
+  import mx.collections.ArrayCollection;
+  import mx.collections.ICollectionView;
+  import mx.collections.IList;
+  import mx.controls.scrollClasses.ScrollBar;
+  import mx.core.IFactory;
+  import mx.core.ScrollControlBase;
+  import mx.core.UIComponent;
+  import mx.events.CollectionEvent;
+  import mx.events.CollectionEventKind;
+  import mx.events.ScrollEvent;
+  import mx.styles.CSSStyleDeclaration;
+  import mx.styles.StyleManager;
+
+  [Event(name="itemScroll", type="gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.LayoutScrollEvent")]
+  [Event(name="pixelScroll", type="gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.LayoutScrollEvent")]
+  //[Event(name="scroll", type="mx.events.ScrollEvent")]
+
+  /**
+   *  Length of the transition when moving around the canvas.
+   *
+   *  @default 250
+   */
+  [Style(name="moveDuration", type="Number", format="Time", inherit="yes")]
+
+  /**
+   *  An easing function to control the canvas movment transition. Easing functions can
+   *  be used to control the acceleration and deceleration of the transition.
+   *
+   *  @default undefined
+   */
+  [Style(name="moveEasingFunction", type="Function", inherit="yes")]
+
+
+  /**
+   *  Name of CSS style declaration that specifies styles for the schedule entries
+   */
+  [Style(name="entryStyleName", type="String", inherit="yes")]
+
+  /**
+   *  The color of the horizontal grid lines.
+   *  @default 0x666666
+   */
+  [Style(name="dottedGridLines", type="Boolean", inherit="yes")]
+  [Style(name="horizontalGridLineThickness", type="Number", format="Length", inherit="yes")]
+  [Style(name="horizontalGridLineColor", type="uint", format="Color", inherit="yes")]
+  [Style(name="horizontalGridLineAlpha", type="Number", inherit="yes")]
+
+  [Style(name="verticalGridLineThickness", type="Number", format="Length", inherit="yes")]
+  [Style(name="verticalGridLineColor", type="uint", format="Color", inherit="yes")]
+  [Style(name="verticalGridLineAlpha", type="Number", inherit="yes")]
+
+  /**
+   * ScheduleViewer is the main scheduling component. It allows you to render and manipulate
+   * schedule entries in an efficient and very customizable way.
+   * <p><strong>ScheduleViewerSample1 - Introduction</strong></p>
+   * <p>
+   * The ScheduleViewerSample1.mxml in the example section shows how to setup
+   * a ScheduleViewer with default values and 3 entries.
+   * </p>
+   * <p>
+   * To render schedule entries the dataProvider property by default accepts a collection of
+   * charts.scheduling.scheduleClasses.IScheduleEntry objects.
+   * ScheduleViewerSample1 uses charts.scheduling.scheduleClasses.SimpleScheduleEntry,
+   * an implementation of IScheduleEntry.
+   * </p>
+   * <p>
+   * The dataProvider item gets passed into the entryRenderer, which by default
+   * is charts.scheduling.scheduleClasses.renderers.GradientScheduleEntryRenderer.mxml.
+   * You can customize various styles of the entry renderer via the entryStyleName style of ScheduleViewer.
+   * In ScheduleViewerSample1, we use the default styles but there is an example CSS inlcuded.
+   * Try to assign the included myEntryStyle class selector to the entryStyleName style property
+   * of the ScheduleViewer instance.
+   * </p>
+   * <p>
+   * In addition, for maximum flexibility, you can provide a fully customized entry renderer
+   * via the entryRenderer property. The entryRenderer has to implement
+   * charts.scheduling.scheduleClasses.renderers.IScheduleEntryRenderer.
+   * </p>
+   * <p>
+   * ScheduleViewer layouts the entries according to the rules of a layout manager. You can
+   * specify the layout manager with the entryLayout property. Furthermore,
+   * the layout manager can handle any changes that occur to the data provider as any updates,
+   * additions, deletions etc to the entries.
+   * </p>
+   * <p>
+   * By default, the charts.scheduling.scheduleClasses.layout.BestFitLayout
+   * is used, which assigns entries to the top most rows without causing any overlaps
+   * between entries.
+   * </p>
+   * <p><strong>ScheduleViewerSample2 - Layout Manager: SimpleLayout</strong></p>
+   * <p>
+   * Another supplied layout manager is the
+   * charts.scheduling.scheduleClasses.layout.SimpleLayout which places entries exactly as
+   * defined in the dataProvider. This means, that when using SimpleLayout, each item
+   * of the dataProvider is expected to be of type mx.collection.IList since it represents a row.
+   * Each row IList collection is expected to contain IScheduleEntry objects.
+   * You can write your own layout manager, check the BestFitLayout and SimpleLayout and their
+   * base classes and implemented interfaces for how to do that.
+   * </p>
+   * <p>
+   * The ScheduleViewerSample2.mxml shows how to setup
+   * a ScheduleViewer with the supplied SimpleLayout manager. Notice the different structure of
+   * the dataProvider, which now exactly determines how entries are being laid out.
+   * Furthermore, SimpleLayout does not check entries for overlapping. Therefore,
+   * in the second row of ScheduleViewerSample2 you can see one entry overlapping.
+   * </p>
+   * <p>
+   * Notice that we use a different entry renderer in ScheduleViewerSample2.
+   * Instead the default gradient renderer we now use
+   * charts.scheduling.scheduleClasses.renderers.SolidScheduleEntryRenderer
+   * </p>
+   * <p><strong>ScheduleViewerSample3 - Adding Navigation and Zooming</strong></p>
+   * <p>
+   * The ScheduleViewerSample3 sample shows how to add a navigation and a zooming tool.
+   * In order to achieve maximum flexibility both features are meant to be
+   * driven by external components that talk to an API of ScheduleViewer.</p>
+   * <p><em>Zooming</em></p>
+   * <p>
+   * The ScheduleViewer's zoom property can be manipulated in order to achieve zooming.
+   * You could use i.e. a mx:HSlider component that manipulates zoom on each change event
+   * as the ScheduleViewerSample3 example shows. A zoom value of 100 always shows the complete
+   * dataProvider on the currently visible canvas (no scrollbars have to appear).</p>
+   * <p><em>Navigation</em></p>
+   * <p>
+   * The ScheduleViewer's xPosition and yPosition properties can be manipulated in order
+   * to navigate along ScheduleViewer's content.
+   * You could use the scroll events of the Timeline component and the pixelScroll events
+   * of ScheduleViewer to connect both components and achieve navigation via Timeline.
+   * </p>
+   * <p>
+   * ScheduleViewer offers APIs to navigate (and animate) to specific entries or times.
+   * See the gotoNow and gotoSelectedEntry methods of ScheduleViewerSample3.
+   * </p>
+   * <p>
+   * You can select single or multiple entries via the selectedItem and selectedItems property.
+   * To switch to the multiple selection mode, set the allowMultipleSelection to true.
+   * </p>
+   * <p>
+   * Furthermore, in this example, the background color of each schedule entry shall be
+   * data provider driven. To make this possible, we've specified another supplied entry renderer;
+   * charts.scheduling.scheduleClasses.renderers.ColoredGradientScheduleEntryRenderer.
+   * This enry renderer accepts only charts.scheduling.scheduleClasses.ColoredScheduleEntry objects.
+   * We've extracted the creation of schedule entries (of type ColoredScheduleEntry)
+   * into a separate class. Check out charts.scheduling.samples.ScheduleData in the example
+   * section below.
+   * </p>
+   * <p><strong>ScheduleViewerSample4 - Adding Background areas</strong></p>
+   * <p>
+   * You can add customized background areas to ScheduleViewer using the backgroundItems property.
+   * backgroundItems expects an Array of BackgroundItem objects. You can specify a time range,
+   * a color and a description. The latter will be used as a tool tip when the user mouses over
+   * area.
+   * </p>
+   * <p>
+   * For further customizations of the background area in ScheduleViewer, you could
+   * create your customized version of the background layout manager via the backgroundLayout property.
+   * Take a look into the default layout manager
+   * charts.scheduling.scheduleClasses.layout.BackgroundLayout for more information.
+   * i.e. you could add a colored current time area, which moves by the current time.
+   * </p>
+   * <p>
+   * You can also customize the background grid via the supplied styles. See style section.
+   * To customize further, you could define custom layout managers via the
+   * horizontalLinesLayout and verticalLinesLayout properties. See default implementation is
+   * charts.scheduling.scheduleClasses.layout.HorizontalLinesLayout and
+   * charts.scheduling.scheduleClasses.layout.VerticalLinesLayout. i.e. you could
+   * add thicker horizontal lines, after certain items.</p>
+   * <p><strong>ScheduleViewerSample5 - Row based schedulers</strong></p>
+   * <p>
+   * ScheduleViewerSample5 shows how you can synchronize a List control
+   * with ScheduleViewer. The pixelScrollEnabled flag lets ScheduleViewer
+   * scroll on rows instead of pixels. Animations are still supported for pixels. The itemScroll
+   * and pixelScroll events allow to connect external components to ScheduleViewer such as the List
+   * shown in this example.</p>
+   * <p><strong>ScheduleViewerSample6 - Customization of background lines</strong></p>
+   * <p>
+   * ScheduleViewerSample6 shows how you can customize vertical and
+   * horizontal background lines with the exposed horizontalLinesViewer and
+   * verticalLinesViewer properties of ScheduleViewer. The custom viewers used in this
+   * example are
+   * charts.scheduling.samples.AlternatingHorizontalLinesViewer and
+   * charts.scheduling.samples.SolidVerticalLinesViewer</p>
+   *
+   * @see charts.scheduling.scheduleClasses.IScheduleEntry
+   * @see charts.scheduling.scheduleClasses.SimpleScheduleEntry
+   * @see charts.scheduling.scheduleClasses.ColoredScheduleEntry
+   * @see charts.scheduling.scheduleClasses.renderers.GradientScheduleEntryRenderer
+   * @charts.scheduling.scheduleClasses.renderers.ColoredGradientScheduleEntryRenderer
+   * @see charts.scheduling.scheduleClasses.renderers.SolidScheduleEntryRenderer
+   * @see charts.scheduling.scheduleClasses.renderers.IScheduleEntryRenderer
+   * @see charts.scheduling.scheduleClasses.layout.BestFitLayout
+   * @see charts.scheduling.scheduleClasses.layout.SimpleLayout
+   * @see charts.scheduling.scheduleClasses.layout.BackgroundLayout
+   * @see charts.scheduling.scheduleClasses.BackgroundItem
+   * @see charts.scheduling.scheduleClasses.layout.HorizontalLinesLayout
+   * @see charts.scheduling.scheduleClasses.layout.VerticalLinesLayout
+   * @see charts.scheduling.controls.Timeline
+   * @see charts.scheduling.util.DateUtil
+   *
+   */
+  public class ScheduleViewer extends ScrollControlBase
+  {
+    protected var collection:ICollectionView;
+    public var schedule:Schedule;
+    public var navigator:ScheduleNavigator;
+    private var content:UIComponent;
+    private var _timeRanges:IList;
+    private var _minimumTimeRangeWidth:Number;
+
+    private static var classConstructed:Boolean = classConstruct();
+
+    // Define a static method to initialize the style.
+    private static function classConstruct():Boolean
+    {
+      if (!StyleManager.getStyleDeclaration(".scheduleViewer"))
+      {
+        // If ScheduleViewer has no CSS definition,
+        // create one and set the default value.
+        var newStyleDeclaration:CSSStyleDeclaration = new CSSStyleDeclaration();
+        newStyleDeclaration.setStyle("moveDuration", 1000);
+        newStyleDeclaration.setStyle("dottedGridLines", true);
+        newStyleDeclaration.setStyle("horizontalGridLineThickness", 1);
+        newStyleDeclaration.setStyle("horizontalGridLineColor", 0x000000);
+        newStyleDeclaration.setStyle("horizontalGridLineAlpha", .5);
+        newStyleDeclaration.setStyle("verticalGridLineThickness", 1);
+        newStyleDeclaration.setStyle("verticalGridLineColor", 0x000000);
+        newStyleDeclaration.setStyle("verticalGridLineAlpha", .5);
+
+        StyleManager.setStyleDeclaration(".scheduleViewer", newStyleDeclaration, true);
+      }
+      return true;
+    }
+
+    public function ScheduleViewer()
+    {
+      styleName = "scheduleViewer";
+      schedule = new Schedule(this);
+
+      navigator = new ScheduleNavigator(this);
+      navigator.addEventListener(ScheduleNavigator.INVALIDATE_DISPLAY_LIST, onInvalidateDisplayList);
+
+      schedule.navigator = navigator;
+      schedule.initialize();
+    }
+
+    schedule_internal function get verticalScrollBar():ScrollBar
+    {
+      return verticalScrollBar;
+    }
+
+    /**
+     * @private
+     */
+    override protected function createChildren():void
+    {
+      super.createChildren();
+
+      addEventListener(ScrollEvent.SCROLL, navigator.onScroll);
+      addEventListener(LayoutScrollEvent.PIXEL_SCROLL, scrollHandler);
+
+      content = new UIComponent();
+      schedule.content = content;
+      addChild(content);
+      content.mask = maskShape;
+
+      schedule.initializeCompileTimeViewLayers();
+
+      content.addChild(schedule.backgroundViewer);
+      content.addChild(schedule.entryViewer);
+
+      invalidateProperties();
+    }
+
+    /**
+     * @private
+     */
+    override protected function commitProperties():void
+    {
+      if (!schedule.isViewlayersInitialized)
+      {
+        schedule.isViewlayersInitialized = true;
+        if (isNaN(contentWidth) && width != 0)
+          contentWidth = width;
+        schedule.initializeRuntimeViewLayers();
+      }
+    }
+
+    /**
+     * @private
+     */
+    override protected function updateDisplayList(
+      unscaledWidth:Number,
+      unscaledHeight:Number):void
+    {
+      super.updateDisplayList(unscaledWidth, unscaledHeight);
+
+      //other layouters get updated by entryLayoutImpl.
+      schedule.entryLayoutImpl.viewportWidth = unscaledWidth;
+      schedule.entryLayoutImpl.viewportHeight = unscaledHeight;
+      schedule.entryLayoutImpl.update();
+
+      navigator.updateItemScroll();
+
+      setScrollBarProperties(
+        schedule.entryLayoutImpl.contentWidth + navigator.contentWidthOffset, unscaledWidth,
+        schedule.entryLayoutImpl.contentHeight + navigator.contentHeightOffset, unscaledHeight);
+    }
+
+    /**
+     * @private
+     */
+    override public function styleChanged(styleProp:String):void
+    {
+      super.styleChanged(styleProp);
+      if (styleProp != null)
+      {
+        if (Object(schedule.horizontalLinesViewerImpl).hasOwnProperty(styleProp))
+        {
+          schedule.horizontalLinesViewerImpl[styleProp] = getStyle(styleProp);
+        }
+        if (Object(schedule.verticalLinesViewerImpl).hasOwnProperty(styleProp))
+        {
+          schedule.verticalLinesViewerImpl[styleProp] = getStyle(styleProp);
+        }
+      }
+
+      var entryStyleName:String = getStyle("entryStyleName");
+      if (entryStyleName)
+      {
+        schedule.entryViewer.setStyle("entryStyleName", entryStyleName);
+      }
+    }
+
+    /**
+     * @private
+     */
+    protected function modelChangedHandler(event:CollectionEvent):void
+    {
+      if (schedule.isViewlayersInitialized)
+      {
+        var entryLayoutImpl:IEntryLayout = IEntryLayout(schedule.entryLayoutImpl);
+        if (event.kind == CollectionEventKind.ADD)
+        {
+          entryLayoutImpl.addItem(event);
+        }
+        else if (event.kind == CollectionEventKind.REMOVE)
+        {
+          entryLayoutImpl.removeItem(event);
+        }
+        else if (event.kind == CollectionEventKind.REPLACE)
+        {
+          entryLayoutImpl.replaceItem(event);
+        }
+        else if (event.kind == CollectionEventKind.UPDATE)
+        {
+          entryLayoutImpl.updateItem(event);
+        }
+        else if (event.kind == CollectionEventKind.REFRESH)
+        {
+          entryLayoutImpl.refreshItem(event);
+        }
+        else if (event.kind == CollectionEventKind.RESET)
+        {
+          entryLayoutImpl.resetItem(event);
+        }
+        else if (event.kind == CollectionEventKind.MOVE)
+        {
+          entryLayoutImpl.moveItem(event);
+        }
+        invalidateDisplayList();
+      }
+    }
+
+    override protected function mouseWheelHandler(event:MouseEvent):void
+    {
+      if (verticalScrollBar)
+      {
+        event.stopPropagation();
+        navigator.mouseWheelHandler(event);
+      }
+    }
+
+    override protected function scrollHandler(event:Event):void
+    {
+      navigator.scrollHandler(event);
+    }
+
+    public function get dataProvider():Object
+    {
+      return collection;
+    }
+
+    public function set dataProvider(value:Object):void
+    {
+      if (collection)
+      {
+        collection.removeEventListener(CollectionEvent.COLLECTION_CHANGE, modelChangedHandler);
+      }
+      if (value is ICollectionView)
+      {
+        collection = ICollectionView(value);
+      }
+      else if (value is Array)
+      {
+        collection = new ArrayCollection(value as Array);
+      }
+      else
+      {
+        // convert it to an array containing this one item
+        var tmp:Array = [];
+        if (value != null)
+          tmp.push(value);
+        collection = new ArrayCollection(tmp);
+      }
+
+      collection.addEventListener(CollectionEvent.COLLECTION_CHANGE, modelChangedHandler);
+
+      var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+      event.kind = CollectionEventKind.RESET;
+      schedule.initializeEntryLayout();
+      modelChangedHandler(event);
+      dispatchEvent(event);
+    }
+
+    [Bindable]
+    public function get startDate():Date
+    {
+      return schedule.entryLayoutImpl.startDate;
+    }
+
+    public function set startDate(value:Date):void
+    {
+      schedule.entryLayoutImpl.startDate = value;
+      invalidateDisplayList();
+    }
+
+    [Bindable]
+    public function get endDate():Date
+    {
+      return schedule.entryLayoutImpl.endDate;
+    }
+
+    public function set endDate(value:Date):void
+    {
+      schedule.entryLayoutImpl.endDate = value;
+      invalidateDisplayList();
+    }
+
+    [Bindable]
+    public function get timeRanges():IList
+    {
+      return _timeRanges;
+    }
+
+    public function set timeRanges(value:IList):void
+    {
+      _timeRanges = value;
+      schedule.backgroundLayoutImpl.timeRanges = _timeRanges;
+      schedule.verticalLinesLayoutImpl.timeRanges = _timeRanges;
+      invalidateDisplayList();
+    }
+
+    [Bindable]
+    public function get minimumTimeRangeWidth():Number
+    {
+      return _minimumTimeRangeWidth;
+    }
+
+    public function set minimumTimeRangeWidth(value:Number):void
+    {
+      _minimumTimeRangeWidth = value;
+      schedule.backgroundLayoutImpl.minimumTimeRangeWidth = _minimumTimeRangeWidth;
+      schedule.verticalLinesLayoutImpl.minimumTimeRangeWidth = _minimumTimeRangeWidth;
+      invalidateDisplayList();
+    }
+
+    [Bindable]
+    public function get rowHeight():Number
+    {
+      return schedule.entryLayoutImpl.rowHeight;
+    }
+
+    public function set rowHeight(value:Number):void
+    {
+      schedule.entryLayoutImpl.rowHeight = value;
+      schedule.entryLayoutImpl.createLayout();
+      invalidateDisplayList();
+    }
+
+    [Bindable]
+    public function get selectedItem():IScheduleEntry
+    {
+      return schedule.entryViewer.selectedItem;
+    }
+
+    public function set selectedItem(value:IScheduleEntry):void
+    {
+      schedule.entryViewer.selectedItem = value;
+    }
+
+    [Bindable]
+    public function get selectedItems():Array
+    {
+      return schedule.entryViewer.selectedItems;
+    }
+
+    public function set selectedItems(value:Array):void
+    {
+      schedule.entryViewer.selectedItems = value;
+    }
+
+    [Bindable]
+    public function get allowMultipleSelection():Boolean
+    {
+      return schedule.entryViewer.allowMultipleSelection;
+    }
+
+    public function set allowMultipleSelection(value:Boolean):void
+    {
+      schedule.entryViewer.allowMultipleSelection = value;
+    }
+
+    [Bindable]
+    public function get backgroundItems():IList
+    {
+      return schedule.backgroundLayoutImpl.backgroundItems
+    }
+
+    public function set backgroundItems(value:IList):void
+    {
+      schedule.backgroundLayoutImpl.backgroundItems = value;
+    }
+
+    //Core--------------------------
+
+    [Bindable]
+    public function get entryLayout():IFactory
+    {
+      return schedule.entryLayout;
+    }
+
+    public function set entryLayout(value:IFactory):void
+    {
+      schedule.entryLayout = value;
+    }
+
+    [Bindable]
+    public function get entryRenderer():IFactory
+    {
+      return schedule.entryRenderer;
+    }
+
+    public function set entryRenderer(value:IFactory):void
+    {
+      schedule.entryRenderer = value;
+    }
+
+    [Bindable]
+    public function get backgroundLayout():IFactory
+    {
+      return schedule.backgroundLayout;
+    }
+
+    public function set backgroundLayout(value:IFactory):void
+    {
+      schedule.backgroundLayout = value;
+    }
+
+    [Bindable]
+    public function get horizontalLinesLayout():IFactory
+    {
+      return schedule.horizontalLinesLayout;
+    }
+
+    public function set horizontalLinesLayout(value:IFactory):void
+    {
+      schedule.horizontalLinesLayout = value;
+    }
+
+    [Bindable]
+    public function get horizontalLinesViewer():IFactory
+    {
+      return schedule.horizontalLinesViewer;
+    }
+
+    public function set horizontalLinesViewer(value:IFactory):void
+    {
+      schedule.horizontalLinesViewer = value;
+    }
+
+    [Bindable]
+    public function get verticalLinesLayout():IFactory
+    {
+      return schedule.verticalLinesLayout;
+    }
+
+    public function set verticalLinesLayout(value:IFactory):void
+    {
+      schedule.verticalLinesLayout = value;
+    }
+
+    [Bindable]
+    public function get verticalLinesViewer():IFactory
+    {
+      return schedule.verticalLinesViewer;
+    }
+
+    public function set verticalLinesViewer(value:IFactory):void
+    {
+      schedule.verticalLinesViewer = value;
+    }
+
+    //Navigation--------------------------
+
+    [Bindable]
+    public function get zoom():Number
+    {
+      return navigator.zoom;
+    }
+
+    public function set zoom(value:Number):void
+    {
+      navigator.zoom = value;
+    }
+
+    [Bindable]
+    public function get contentWidth():Number
+    {
+      return navigator.contentWidth;
+    }
+
+    public function set contentWidth(value:Number):void
+    {
+      navigator.contentWidth = value;
+    }
+
+    [Bindable]
+    public function get xPosition():Number
+    {
+      return navigator.xPosition;
+    }
+
+    public function set xPosition(value:Number):void
+    {
+      navigator.xPosition = value;
+    }
+
+    [Bindable]
+    public function get yPosition():Number
+    {
+      return navigator.yPosition;
+    }
+
+    public function set yPosition(value:Number):void
+    {
+      navigator.yPosition = value;
+    }
+
+    [Bindable]
+    public function get xPositionWithOffset():Number
+    {
+      return navigator.xPositionWithOffset;
+    }
+
+    public function set xPositionWithOffset(value:Number):void
+    {
+      navigator.xPositionWithOffset = value;
+    }
+
+    [Bindable]
+    public function get yPositionWithOffset():Number
+    {
+      return navigator.yPositionWithOffset;
+    }
+
+    public function set yPositionWithOffset(value:Number):void
+    {
+      navigator.yPositionWithOffset = value;
+    }
+
+    [Bindable]
+    public function get xOffset():Number
+    {
+      return navigator.xOffset;
+    }
+
+    public function set xOffset(value:Number):void
+    {
+      navigator.xOffset = value;
+    }
+
+    [Bindable]
+    public function get yOffset():Number
+    {
+      return navigator.yOffset;
+    }
+
+    public function set yOffset(value:Number):void
+    {
+      navigator.yOffset = value;
+    }
+
+    [Bindable]
+    public function get pixelScrollEnabled():Boolean
+    {
+      return navigator.pixelScrollEnabled;
+    }
+
+    public function set pixelScrollEnabled(value:Boolean):void
+    {
+      navigator.pixelScrollEnabled = value;
+    }
+
+    public function gotoTime(milliseconds:Number):void
+    {
+      navigator.gotoTime(milliseconds);
+    }
+
+    public function moveToTime(milliseconds:Number):void
+    {
+      navigator.moveToTime(milliseconds);
+    }
+
+    public function gotoEntry(entry:IScheduleEntry):void
+    {
+      navigator.gotoEntry(entry);
+    }
+
+    public function moveToEntry(entry:IScheduleEntry):void
+    {
+      navigator.moveToEntry(entry);
+    }
+
+    private function onInvalidateDisplayList(event:Event):void
+    {
+      invalidateDisplayList();
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/ScheduleData.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/ScheduleData.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/ScheduleData.as	(revision 15)
@@ -0,0 +1,140 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.samples
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.SimpleScheduleEntry;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.ColoredScheduleEntry;
+	import gssim.gssimstudio.editor.charts.scheduling.util.DateUtil;
+	
+	import mx.collections.ArrayCollection;
+	import mx.collections.IList;
+	
+	public class ScheduleData
+	{	
+		public function createRandomSimpleScheduleEntries( size : Number ) : ArrayCollection
+		{
+			var result : Array = new Array();
+			
+			for( var i : Number = 0; i < size; i++ )
+			{
+				result.push( createSimpleEntry( 
+					i, 
+					randomInt( ( 24 - 1 ) * 60 ) * 60 * 1000,								
+					( 10 + randomInt( 120 ) ) * 60 * 1000 ) );
+			}
+			
+			return new ArrayCollection( result );			
+		}
+		
+		public function createRandomColoredScheduleEntries( size : Number ) : ArrayCollection
+		{
+			var result : Array = new Array();
+			
+			for( var i : Number = 0; i < size; i++ )
+			{
+				var color : uint = 0x999999 + randomInt( 0x777777 );
+				result.push( createColoredEntry( 
+					i, 
+					randomInt( ( 24 - 1 ) * 60 ) * 60 * 1000,								
+					( 10 + randomInt( 120 ) ) * 60 * 1000, color ) );
+			}
+			
+			return new ArrayCollection( result );			
+		}
+		
+		public function createRowsOfRandomColoredEntries( rows : Number, size : Number ) : ArrayCollection
+		{
+			var result : Array = new Array();			
+			for( var i : Number = 0; i < rows; i++ )
+			{
+				var row : IList = new ArrayCollection();				
+				for( var j : Number = 0; j < size; j++ )
+				{
+					var color : uint = 0x999999 + randomInt( 0x777777 );
+					row.addItem( createColoredEntry( 
+						j, 
+						randomInt( ( 24 - 1 ) * 60 ) * 60 * 1000,								
+						( 10 + randomInt( 60 ) ) * 60 * 1000, color ) );
+				}
+				result.push( row );
+			}			
+			return new ArrayCollection( result );			
+		}
+		
+		public function createRowsOfSequentialColoredEntries( rows : Number, size : Number ) : ArrayCollection
+		{
+			var result : Array = new Array();
+			var counter : Number = 0;		
+			for( var i : Number = 0; i < rows; i++ )
+			{				
+				var row : IList = new ArrayCollection();
+				var currentTime : Number = ( ( 24 - 1 ) * 60 ) / size;
+				var color : uint = 0x999999 + randomInt( 0x777777 );
+				for( var j : Number = 0; j < size; j++ )
+				{
+					counter++;
+					var startTime : Number = currentTime * j * 60 * 1000;
+					var duration : Number = ( randomInt( 60 ) + 30 ) * 60 * 1000;					
+					var entry : SimpleScheduleEntry = createColoredEntry( j, startTime, duration, color );										
+					entry.label = "Entry " + counter;
+					row.addItem( entry );
+				}
+				result.push( row );
+			}			
+			return new ArrayCollection( result );			
+		}		
+		
+		private function createSimpleEntry( i : Number, startTime : Number, duration : Number ) : SimpleScheduleEntry
+		{
+			var entry : SimpleScheduleEntry = new SimpleScheduleEntry();
+			entry.startDate = DateUtil.setTime( new Date(), startTime );
+			entry.endDate = DateUtil.addTime( DateUtil.copyDate( entry.startDate ), duration );
+			entry.label = "Entry " + i; 
+			return entry;
+		}
+		
+		private function createColoredEntry( i : Number, startTime : Number, duration : Number, color : uint ) : SimpleScheduleEntry
+		{
+			var entry : ColoredScheduleEntry = new ColoredScheduleEntry();
+			entry.startDate = DateUtil.setTime( new Date(), startTime );
+			entry.endDate = DateUtil.addTime( DateUtil.copyDate( entry.startDate ), duration );
+			entry.label = "Entry " + i;
+			entry.backgroundColor = color;
+			return entry;
+		}		
+		
+		private function randomInt( max : Number ) : Number
+		{
+			return Math.floor( Math.random() * max );
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/AlternatingHorizontalLinesViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/AlternatingHorizontalLinesViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/AlternatingHorizontalLinesViewer.as	(revision 15)
@@ -0,0 +1,25 @@
+package gssim.gssimstudio.editor.charts.scheduling.samples
+{	
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.HorizontalLinesLayoutItem;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IHorizontalLinesLayout;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.ILineRenderer;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers.HorizontalLinesViewer;
+	
+	public class AlternatingHorizontalLinesViewer extends HorizontalLinesViewer
+	{
+		override protected function render( layout : IHorizontalLinesLayout ) : void 
+		{
+			var lineRenderer : ILineRenderer = super.getLineRendererForStyling();
+			
+			var length : Number = layout.items.length;
+			for( var i : int = 0; i < length; i++ )
+			{
+				var item : HorizontalLinesLayoutItem = layout.items[ i ];
+				var currentRow : Number = Math.floor( item.y / layout.rowHeight );
+				lineRenderer.weight = currentRow % 2 ? 0 : 2;
+				
+				super.drawLineForItem( item, lineRenderer );
+			}
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/SolidVerticalLinesViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/SolidVerticalLinesViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/samples/SolidVerticalLinesViewer.as	(revision 15)
@@ -0,0 +1,25 @@
+package gssim.gssimstudio.editor.charts.scheduling.samples
+{	
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IVerticalLinesLayout;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.VerticalLinesLayoutItem;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.ILineRenderer;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.LineRenderer;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers.VerticalLinesViewer;
+	
+	public class SolidVerticalLinesViewer extends VerticalLinesViewer 
+	{
+		override protected function render( layout : IVerticalLinesLayout ) : void 
+		{
+			var lineRenderer : ILineRenderer = new LineRenderer();
+			lineRenderer.weight = verticalGridLineThickness;
+			lineRenderer.color = verticalGridLineColor;
+			lineRenderer.alpha = verticalGridLineAlpha;
+			
+			for each( var item : VerticalLinesLayoutItem in layout.items )
+			{
+				super.drawLineForItem( item, lineRenderer );
+			}
+		}		
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineLayout.as	(revision 15)
@@ -0,0 +1,132 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.timelineClasses
+{	
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.ILayoutProvider;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.Layout;
+	import gssim.gssimstudio.editor.charts.scheduling.util.DateUtil;
+	
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	
+	import mx.collections.ArrayCollection;
+	import mx.collections.IList;
+	
+	[Event ("update")]
+	
+	/**
+	 * @private
+	 */
+	public class TimelineLayout extends Layout implements ILayoutProvider
+	{
+		public var timeRanges : IList;
+		public var minimumTimeRangeWidth : Number = 80;
+		[Bindable]
+		public var currentDate : Date;
+		
+		private var _contentWidth : Number;
+		
+		public function TimelineLayout() 
+		{
+			timeRanges = TimeRangeDescriptorUtil.getDefaultTimeRangeDescriptor();
+		}
+		
+		[Bindable]
+		override public function get contentWidth() : Number 
+		{
+			return _contentWidth;
+		}
+		
+		override public function set contentWidth( value : Number ) : void
+		{
+			xPosition *= ( value / _contentWidth );
+			_contentWidth = value;
+		}
+
+		public function update() : void
+		{
+			calculateItems(); 
+			dispatchEvent( new Event("update") );
+		}
+		
+		private function calculateItems() : void
+		{
+			var totalMilliseconds : Number = _endDate - _startDate;
+			var entry : ITimeDescriptor = getTimeDescriptor( contentWidth, totalMilliseconds );	
+			var millisecondsPerColumn : Number = entry.date.getTime();
+			//var numberOfItems : Number = Math.floor( totalMilliseconds / millisecondsPerColumn ) + 1;
+			var numberOfItems : Number = totalMilliseconds / millisecondsPerColumn;
+			var columnWidth : Number = contentWidth / numberOfItems;			
+			if( columnWidth < minimumTimeRangeWidth ) columnWidth = minimumTimeRangeWidth;
+			
+			_items = new ArrayCollection();
+			var firstIndex : Number = Math.floor( xPosition / columnWidth );
+			var lastIndex : Number = Math.ceil( ( xPosition + viewportWidth ) / columnWidth );
+			for( var i : Number = firstIndex; i <= lastIndex; i++ )
+			{
+				var item : TimelineLayoutItem = new TimelineLayoutItem();
+				
+				item.width = columnWidth;
+				item.height = viewportHeight;
+				item.x = i * columnWidth;
+            item.y = 0;
+            
+				currentDate = new Date( i * millisecondsPerColumn + _startDate );
+				
+				var data : ITimeDescriptor = new SimpleTimeDescriptor();
+				data.description = entry.description;
+				data.date = currentDate;				
+				item.data = data;
+				
+				_items.addItem( item );
+			}
+		}
+		
+		/**
+		 * try to find the smallest unit, which is wider than the minimumTimeRangeWidth
+		 */
+		private function getTimeDescriptor( totalWidth : Number, totalMilliseconds : Number ) : ITimeDescriptor
+		{
+			var length : Number = timeRanges.length;
+			for( var i : Number = 0; i < length; i++ )
+			{
+				var entry : ITimeDescriptor = ITimeDescriptor( timeRanges.getItemAt( i ) );
+				var step : Number = entry.date.getTime();
+				var width : Number = step / totalMilliseconds * totalWidth;
+				if( width >= minimumTimeRangeWidth )
+				{
+					return entry;
+				}
+			}
+			return ITimeDescriptor( timeRanges.getItemAt( length - 1 ) );
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/ITimeDescriptor.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/ITimeDescriptor.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/ITimeDescriptor.as	(revision 15)
@@ -0,0 +1,40 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.timelineClasses
+{	
+	public interface ITimeDescriptor
+	{
+		function get date() : Date;
+		function set date( value : Date ) : void;
+		function get description() : Object;
+		function set description ( value : Object ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/SimpleTimeDescriptor.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/SimpleTimeDescriptor.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/SimpleTimeDescriptor.as	(revision 15)
@@ -0,0 +1,58 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.timelineClasses
+{
+	public class SimpleTimeDescriptor implements ITimeDescriptor
+	{
+		private var _date : Date;
+		private var _description : Object;
+		
+		public function get date() : Date
+		{
+			return _date;
+		}
+		
+		public function set date( value : Date ) : void
+		{
+			_date = value;
+		}
+		
+		public function get description() : Object
+		{
+			return _description;
+		}
+		
+		public function set description ( value : Object ) : void
+		{
+			_description = value;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/ITimelineEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/ITimelineEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/ITimelineEntryRenderer.as	(revision 15)
@@ -0,0 +1,40 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.timelineClasses
+{
+	import mx.core.IDataRenderer;
+	import mx.core.IFlexDisplayObject;
+	
+	public interface ITimelineEntryRenderer extends IFlexDisplayObject, IDataRenderer
+	{
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimeRangeDescriptorUtil.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimeRangeDescriptorUtil.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimeRangeDescriptorUtil.as	(revision 15)
@@ -0,0 +1,86 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.timelineClasses
+{
+	import gssim.gssimstudio.editor.charts.scheduling.util.DateUtil;
+	
+	import mx.collections.ArrayCollection;
+	import mx.collections.IList;
+	
+	public class TimeRangeDescriptorUtil
+	{		
+		public static var defaultTimeRangeDescriptor : Array = [ 
+			[ DateUtil.MINUTE_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 5 * DateUtil.MINUTE_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 10 * DateUtil.MINUTE_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 15 * DateUtil.MINUTE_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 30 * DateUtil.MINUTE_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 60 * DateUtil.MINUTE_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 2 * DateUtil.HOUR_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 6 * DateUtil.HOUR_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 12 * DateUtil.HOUR_IN_MILLISECONDS, "L:NNAA" ], 
+			[ 24 * DateUtil.HOUR_IN_MILLISECONDS, "DD/MM/YY" ], 
+			[ 2 * DateUtil.DAY_IN_MILLISECONDS, "DD/MM/YY" ],
+			[ 4 * DateUtil.DAY_IN_MILLISECONDS, "DD/MM/YY" ], 	
+			[ 7 * DateUtil.DAY_IN_MILLISECONDS, "DD/MM/YY" ], 
+			[ 14 * DateUtil.DAY_IN_MILLISECONDS, "DD/MM/YY" ],	
+			[ 30 * DateUtil.DAY_IN_MILLISECONDS, "MMM YY" ], 				
+			[ 4 * DateUtil.MONTH_IN_MILLISECONDS, "MMM YY" ],
+			[ 6 * DateUtil.MONTH_IN_MILLISECONDS, "MMM YY" ],
+			[ 9 * DateUtil.MONTH_IN_MILLISECONDS, "MMM YY" ],
+			[ 12 * DateUtil.MONTH_IN_MILLISECONDS, "MMM YY" ],
+			[ 2 * DateUtil.YEAR_IN_MILLISECONDS, "YYYY" ],
+			[ 5 * DateUtil.YEAR_IN_MILLISECONDS, "YYYY" ],
+			[ 10 * DateUtil.YEAR_IN_MILLISECONDS, "YYYY" ],
+			[ 25 * DateUtil.YEAR_IN_MILLISECONDS, "YYYY" ], 
+			[ 500 * DateUtil.YEAR_IN_MILLISECONDS, "YYYY" ] ];
+															
+		public static function convertArrayToTimeRangeDescriptor( timeDescriptor : Array ) : IList 
+		{
+			var dataProvider : IList = new ArrayCollection();
+			var len : Number = timeDescriptor.length;
+			for( var i : Number = 0; i < len; i++ )
+			{
+				var item : Array = timeDescriptor[ i ];
+				var entry : ITimeDescriptor = new SimpleTimeDescriptor();
+				entry.date = new Date( item[ 0 ] );
+				entry.description = item[ 1 ];
+				dataProvider.addItem( entry );
+			}
+			return dataProvider;
+		}
+		
+		public static function getDefaultTimeRangeDescriptor() : IList 
+		{
+			return TimeRangeDescriptorUtil.convertArrayToTimeRangeDescriptor( defaultTimeRangeDescriptor );
+		}		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineViewer.as	(revision 15)
@@ -0,0 +1,121 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.timelineClasses
+{
+	import flash.display.DisplayObject;
+	import flash.events.Event;
+
+	import mx.core.ClassFactory;
+	import mx.core.IFactory;
+	import mx.core.UIComponent;	
+	
+	/**
+	 * @private
+	 */
+	public class TimelineViewer extends UIComponent
+	{
+		public var itemRenderer : IFactory;
+		private var freeRenderers : Array;
+		private var visibleRenderers : Array;
+		private var layout : TimelineLayout;		
+		
+		public function TimelineViewer()
+		{
+			itemRenderer = new ClassFactory( SimpleTimelineEntryRenderer );
+			freeRenderers = new Array();
+			visibleRenderers = new Array();			
+		}
+		
+		public function update( event : Event ) : void
+		{
+			layout = event.target as TimelineLayout;
+			invalidateDisplayList();
+		}
+				
+		protected override function updateDisplayList( unscaledWidth : Number, unscaledHeight : Number ) : void
+		{
+			super.updateDisplayList( unscaledWidth , unscaledHeight );
+			render( layout );
+		}
+		
+		private function render( layout : TimelineLayout ) : void 
+		{
+			if( layout == null ) return;
+			
+			var oldRenderers : Array = visibleRenderers;
+			visibleRenderers = new Array();
+			
+			var xPosition : Number = layout.xPosition;
+			
+			for each( var item : TimelineLayoutItem in layout.items )
+			{
+				var renderer : ITimelineEntryRenderer = oldRenderers.pop();
+				if( renderer != null )
+				{
+					renderer.x = item.x - xPosition;
+					renderer.width = item.width;
+					renderer.y = item.y;
+					renderer.data = item.data;
+				}
+				else 
+				{
+					renderer = getRenderer();					
+					renderer.x = item.x - xPosition;
+					renderer.y = item.y;
+					renderer.height = item.height;					
+					renderer.data = item.data;
+					
+					addChild( DisplayObject( renderer ) );
+				}
+				visibleRenderers.push( renderer );
+			}
+			
+			removeUnusedRenderers( oldRenderers );			
+		}
+		
+		private function removeUnusedRenderers( oldRenderers : Array ) : void
+		{
+			for each( var freeRenderer : DisplayObject in oldRenderers )
+			{
+				freeRenderers.push( removeChild( freeRenderer ) );
+			}
+		}
+		
+		private function getRenderer() : ITimelineEntryRenderer
+		{
+			if( freeRenderers.length > 0 )
+			{
+				return freeRenderers.pop();
+			}
+			return itemRenderer.newInstance();
+		}		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/SimpleTimelineEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/SimpleTimelineEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/SimpleTimelineEntryRenderer.as	(revision 15)
@@ -0,0 +1,52 @@
+/*
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+ */
+package gssim.gssimstudio.editor.charts.scheduling.timelineClasses
+{
+  import mx.controls.Label;
+  import mx.formatters.DateFormatter;
+
+  public class SimpleTimelineEntryRenderer extends Label implements ITimelineEntryRenderer
+  {
+    public function SimpleTimelineEntryRenderer()
+    {
+      super();
+      setStyle("textAlign", "center");
+    }
+
+    override public function set data(value:Object):void
+    {
+      var entry:ITimeDescriptor = ITimeDescriptor(value);
+
+      var formatter:DateFormatter = new DateFormatter();
+      formatter.formatString = String(entry.description);
+
+      text = formatter.format(entry.date);
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineLayoutItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineLayoutItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/timelineClasses/TimelineLayoutItem.as	(revision 15)
@@ -0,0 +1,44 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.timelineClasses
+{
+	/**
+	 * @private
+	 */	
+	public class TimelineLayoutItem
+	{
+		public var data : ITimeDescriptor;
+		public var width : Number;
+		public var height : Number;
+		public var x : Number;
+		public var y : Number;		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/Timeline.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/Timeline.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/Timeline.as	(revision 15)
@@ -0,0 +1,349 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling
+{
+	import gssim.gssimstudio.editor.charts.scheduling.timelineClasses.TimelineLayout;
+	import gssim.gssimstudio.editor.charts.scheduling.timelineClasses.TimelineViewer;
+	
+	import flash.events.Event;
+	
+	import mx.collections.IList;
+	import mx.core.IFactory;
+	import mx.core.ScrollControlBase;
+	import mx.core.ScrollPolicy;
+	import mx.core.UIComponent;
+	import mx.events.PropertyChangeEvent;
+	import mx.events.ScrollEvent;
+	import mx.events.ScrollEventDetail;
+	import mx.events.ScrollEventDirection;
+	
+	/**
+	 * 
+	 * Timeline is an independent control that renders and let users interact 
+	 * with a customizable timeframe. Developers can use this component in combinations 
+	 * other components, i.e. to add a timeline to a ScheduleViewer component. See 
+	 * charts.scheduling.ScheduleViewer for more details. 
+	 * <p>
+	 * You can style the layout of the timeline frame and customize and style 
+	 * each item of the timeline. By default, one item of Timeline would be a Label 
+	 * displaying a date. 
+	 * </p>
+	 * <p>
+	 * The rendering of the item can be customized via the itemRenderer property. The itemRenderer has to 
+	 * implement charts.scheduling.timelineClasses.ITimelineEntryRenderer. 
+	 * Via Timeline's timeRanges property you can pass more information to the renderers 
+	 * on specific time ranges. By default a format string as used in mx.formatters.DateFormatter 
+	 * is passed to the renderer depending on what time range is currently displayed. i.e. by default 
+	 * a format string of "L:NNAA" is passed to the renderer when Timeline currently 
+	 * only dispays a time range of one minute. 
+	 * You can customize this with passing your own timeRanges collection. timeRanges 
+	 * must contain items that adhere to the charts.scheduling.timelineClasses.ITimeDescriptor 
+	 * interface. See charts.scheduling.timelineClasses.TimeRangeDescriptorUtil class 
+	 * for more details and utilities on customizations of time ranges. 
+	 * </p>
+	 * Timeline supports zooming via the zoom and contentWidth property.
+	 * <p>
+	 * Currently, only horizontal timelines are supported. 
+	 * </p>
+	 * <!--<a href="examples/TimelineLabSample.html">See the example SWF</a>-->
+	 * @see #itemRenderer
+	 * @see charts.scheduling.timelineClasses.ITimelineEntryRenderer
+	 * @see #timeRanges
+	 * @see charts.scheduling.timelineClasses.ITimeDescriptor
+	 * @see charts.scheduling.timelineClasses.TimeRangeDescriptorUtil
+	 * @see charts.scheduling.ScheduleViewer
+	 * @see charts.scheduling.util.DateUtil
+	 * 
+	 */
+	public class Timeline extends ScrollControlBase
+	{
+		private var timelineLayout : TimelineLayout;
+		private var timelineViewer : TimelineViewer;
+		private var content : UIComponent;
+		private var contentWidthOffset : Number;
+		
+		private var _timeRanges : IList;
+		private var _minimumTimeRangeWidth : Number;
+		private var _zoom : Number;
+		
+		public function Timeline() 
+		{
+			horizontalScrollPolicy = ScrollPolicy.AUTO;
+			verticalScrollPolicy = ScrollPolicy.OFF;
+			contentWidthOffset = 0;
+			createTimelineLayout();			
+		}
+		
+		/**
+		 * @private
+		 */		
+		override protected function createChildren() : void
+		{
+			super.createChildren();
+			
+			addEventListener( ScrollEvent.SCROLL, onScroll );			
+			
+			content = new UIComponent();
+			addChild( content );
+			content.mask = maskShape;				
+			
+			initializeCompileTimeViewLayers();
+			
+			content.addChild( timelineViewer );
+		}
+
+		/**
+		 * @private
+		 */		
+		override protected function measure():void
+		{
+			super.measure();
+			
+			measuredHeight = 20;
+			measuredMinHeight = 20;
+			
+			if( horizontalScrollPolicy != ScrollPolicy.OFF && horizontalScrollBar )
+			{
+				measuredHeight += horizontalScrollBar.minHeight;
+				measuredMinHeight += horizontalScrollBar.minHeight;
+			}
+		}
+
+		/**
+		 * @private
+		 */		
+		override protected function commitProperties() : void
+		{
+			if( isNaN( contentWidth ) && width != 0 ) contentWidth = width;
+		}
+		
+		/**
+		 * @private
+		 */		
+		override protected function updateDisplayList( 
+			unscaledWidth : Number, 
+			unscaledHeight : Number ) : void
+		{
+			super.updateDisplayList( unscaledWidth , unscaledHeight );
+			
+			timelineLayout.viewportWidth = unscaledWidth;
+			timelineLayout.viewportHeight = unscaledHeight;
+			timelineLayout.update();
+			
+			setScrollBarProperties( 
+				timelineLayout.contentWidth + contentWidthOffset, unscaledWidth, 
+				timelineLayout.contentHeight, unscaledHeight );	
+		}
+		
+		[Bindable]
+		public function get timeRanges() : IList
+		{
+			return _timeRanges;
+		}
+		
+		public function set timeRanges( value : IList ) : void
+		{
+			_timeRanges = value;
+			timelineLayout.timeRanges = _timeRanges;
+			invalidateDisplayList();
+		}
+		
+		[Bindable]
+		public function get minimumTimeRangeWidth() : Number
+		{
+			return _minimumTimeRangeWidth;
+		}
+		
+		public function set minimumTimeRangeWidth( value : Number ) : void
+		{
+			_minimumTimeRangeWidth = value;
+			timelineLayout.minimumTimeRangeWidth = _minimumTimeRangeWidth;
+			invalidateDisplayList();
+		}		
+				
+		[Bindable]
+		public function get startDate() : Date
+		{
+			return timelineLayout.startDate;
+		}		
+		
+		public function set startDate( value : Date ) : void
+		{
+			timelineLayout.startDate = value;
+			invalidateDisplayList();
+		}
+		
+		[Bindable]
+		public function get endDate() : Date
+		{
+			return timelineLayout.endDate;
+		}
+		
+		public function set endDate( value : Date ) : void
+		{
+			timelineLayout.endDate = value;
+			invalidateDisplayList();
+		}
+		
+		[Bindable]
+		public function get itemRenderer() : IFactory 
+		{
+			return timelineViewer.itemRenderer;
+		}
+		
+		public function set itemRenderer( value : IFactory ) : void
+		{
+			if( value != null && value != timelineViewer.itemRenderer )
+			{
+				timelineViewer.itemRenderer = value;	
+			}
+		}		
+		
+		//Navigation--------------------------		
+		
+		[Bindable]
+		public function get zoom() : Number
+		{
+			return _zoom;
+		}
+		
+		public function set zoom( value : Number ) : void
+		{
+			_zoom = value;
+			var adjustedValue : Number = value / 100 * Math.sqrt( width );
+			contentWidth = Math.pow( adjustedValue, 2 );
+		}
+		
+		[Bindable]
+		public function get contentWidth() : Number 
+		{
+			return timelineLayout.contentWidth;
+		}
+		
+		public function set contentWidth( value : Number ) : void
+		{
+			horizontalScrollPosition *= value / timelineLayout.contentWidth;
+			if( isNaN( horizontalScrollPosition )) horizontalScrollPosition = 0;						
+			
+			timelineLayout.contentWidth = value;	
+			invalidateDisplayList();
+		}
+		
+		[Bindable(event="xPositionChanged")]
+		public function get xPosition() : Number
+		{
+			return timelineLayout.xPosition;
+		}
+		
+		public function set xPosition( value : Number ) : void
+		{
+			horizontalScrollPosition = value;
+			setXPosition( value );
+			var overlap : Number = timelineLayout.contentWidth - timelineLayout.viewportWidth;
+			if( overlap < value )
+			{
+				contentWidthOffset = value - overlap;
+				invalidateDisplayList();		
+			}	
+		}
+	
+		[Bindable(event="currentDateChanged")]
+		public function get currentDate() : Date
+		{
+			return timelineLayout.currentDate;
+		}
+		
+		public function set currentDate( value : Date ) : void
+		{
+			timelineLayout.currentDate = value;
+		}
+				
+		private function initializeCompileTimeViewLayers() : void
+		{
+			timelineViewer = new TimelineViewer();
+			timelineLayout.addEventListener( "update", timelineViewer.update );
+		}	
+		
+		private function createTimelineLayout() : void
+		{
+			if( timelineLayout == null )
+			{
+				timelineLayout = new TimelineLayout();
+				timelineLayout.addEventListener( "propertyChange", onTimelineLayoutChange );
+			}
+		}
+		
+		private function onTimelineLayoutChange( event : PropertyChangeEvent ) : void
+		{			
+			if( event.property == "xPosition" )
+			{
+				dispatchEvent( new Event( "xPositionChanged" ) );
+			}
+			else if( event.property == "currentDate" )
+			{
+				dispatchEvent( new Event( "currentDateChanged" ) );
+			}
+		}
+		
+		private function onCurrentDateChanged( event : Event ) : void
+		{
+			dispatchEvent( new Event( "onCurrentDateChanged" ) );
+		}
+		
+		private function setHorizontalScrollPosition( value : Number ) : void
+		{
+			if( value > maxHorizontalScrollPosition ) value = maxHorizontalScrollPosition;
+			
+			var event : ScrollEvent = new ScrollEvent( ScrollEvent.SCROLL );
+			event.direction = ScrollEventDirection.HORIZONTAL;
+			event.position = value;
+			event.delta = horizontalScrollPosition - value;
+			event.detail = ScrollEventDetail.THUMB_POSITION;
+			horizontalScrollPosition = value;
+			dispatchEvent( event );
+		}
+		
+		private function onScroll( event : ScrollEvent ) : void
+		{
+			var position : Number = event.position;
+			if( event.direction == ScrollEventDirection.HORIZONTAL )
+			{
+				xPosition = position;
+			}
+		}
+		
+		private function setXPosition( position : Number ) : void
+		{
+			timelineLayout.xPosition = position;
+			timelineLayout.update();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/SimpleScheduleEntry.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/SimpleScheduleEntry.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/SimpleScheduleEntry.as	(revision 15)
@@ -0,0 +1,69 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{	
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+
+	/**
+	 */	
+	public class SimpleScheduleEntry implements IScheduleEntry
+	{
+		public var label : String;
+		
+		private var _startDate : Date;
+		private var _endDate : Date;	
+	
+		public function get startDate() : Date
+		{
+			return _startDate;
+		}
+		
+		public function set startDate( value : Date) : void
+		{
+			_startDate = value;
+		}
+		
+		public function get endDate() : Date
+		{
+			return _endDate;
+		}
+		
+		public function set endDate( value : Date ) : void 
+		{
+			_endDate = value;
+		}
+				
+		public function toString() : String
+		{
+			return "[object SimpleScheduleEntry startDate:" + startDate + " endDate:" + endDate + "]";
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/schedule_internal.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/schedule_internal.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/schedule_internal.as	(revision 15)
@@ -0,0 +1,5 @@
+
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{
+   public namespace schedule_internal = "http://www.adobe.com/ac/scheduling/internal";
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/RowLocatorItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/RowLocatorItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/RowLocatorItem.as	(revision 15)
@@ -0,0 +1,44 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.EntryLayoutItem;
+	
+	/**
+	 * @private
+	 */
+	public class RowLocatorItem
+	{
+		public var row : Number;
+		public var rowItem : Number;
+		public var layoutItem : EntryLayoutItem;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BackgroundLayoutItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BackgroundLayoutItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BackgroundLayoutItem.as	(revision 15)
@@ -0,0 +1,46 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	/**
+	 * @private
+	 */
+	public class BackgroundLayoutItem
+	{		
+		public var backgroundColor : uint;
+		public var toolTip : String;
+		public var width : Number;
+		public var height : Number;
+		public var x : Number;
+		public var y : Number;		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BestFitLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BestFitLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BestFitLayout.as	(revision 15)
@@ -0,0 +1,188 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+	
+	import mx.events.CollectionEvent;
+
+	public class BestFitLayout extends AbstractEntryLayout implements IEntryLayout
+	{
+		/**
+		 * Layout the complete dataProvider so that 
+		 * one millisecond equals one pixel. This is the best 
+		 * precision we can ever show, since Dates have this 
+		 * resolution.
+		 */
+		override public function createLayout() : void
+		{
+			super.createLayout();
+			if( dataProvider == null ) return;
+			createLayoutFor( 0, dataProvider.length );
+		}
+		
+		private function createLayoutFor( startIndex : Number, endIndex : Number ) : void
+		{
+			var len : Number = endIndex;
+			for( var i : Number = startIndex; i < len; i++ )
+			{
+				var item : IScheduleEntry = IScheduleEntry( dataProvider.getItemAt( i ) );
+				addItemToRow( item );
+			}
+			updateLayouterProperties();
+		}
+	
+		private function addItemToRow( entry : IScheduleEntry ) : void
+		{
+			var x : Number = entry.startDate.getTime() - startDate.getTime();
+			if( isOffScreenLeftRight( x, totalMilliseconds ) ) return;
+			
+			var width : Number = entry.endDate.getTime() - entry.startDate.getTime();
+			if( isTooSmall( width ) ) return;
+			
+			var layoutItem : EntryLayoutItem = new EntryLayoutItem();
+			layoutItem.x = x;
+			layoutItem.width = width; 
+			layoutItem.height = rowHeight;
+			layoutItem.data = entry;
+			
+			//sets y and row of the item
+			insertNonOverlapping( layoutItem );
+		}
+				
+		/**
+		 * find the lowest row, which hasn't 
+		 * overlapping items and add the item to it
+		 */ 
+		private function insertNonOverlapping( item : EntryLayoutItem ) : void
+		{
+			//Either find an existing row and squeeze the item into it...
+			var length : Number = rows.length;
+			for ( var rowIndex : Number = 0; rowIndex < length; rowIndex++ )
+			{
+				var row : Array = rows[ rowIndex ];
+				var index : Number = findNonOverlappingPosition( row, item );
+				if( index >= 0 )
+				{
+					item.row = rowIndex;
+					item.y = rowIndex * item.height;
+					row.splice( index, 0, item );
+					//save item against row location for efficient access.
+					saveItemWithRow( item, rowIndex, index );
+					return;
+				}
+			}
+			
+			//...or create a new row and place the item in there.
+			item.row = length;
+			item.y = length * item.height;			
+			var newRow : Array = new Array();
+			newRow.push( item );
+			rows.push( newRow );
+			//save item against row location for efficient access.
+			saveItemWithRow( item, length, 0 );
+		}
+		
+		/**
+		 * See if we can fit the item into this row
+		 * return the index of the inserting point or -1 if no position could be found
+		 * 
+		 * TODO: If we could assume, that the dataProvider is ordererd by startTime, 
+		 * we wouldn't have to search here. Instead we could simply add the items.
+		 */ 
+		private function findNonOverlappingPosition( row : Array, item : EntryLayoutItem ) : Number
+		{
+			var x : Number = item.x;
+			var width : Number = item.width;
+
+			var length : Number = row.length;
+			if( length == 0 ) return 0;
+			
+			var i : Number = 0;
+			while( i < length && x > row[ i ].x ) i++;
+			
+			//x was greater than all of the entries
+			if( i == length )
+			{
+				if( x >= row[ i - 1 ].x + row[ i - 1 ].width )
+				{
+					return length;	
+				}
+				return -1;
+			}
+			//x is lower or equal to the current entry
+			if( x < row[ i ].x && x + width <= row[ i ].x ){
+				if( i == 0 ) return 0;
+				if( x > row[ i - 1 ].x + row[ i - 1 ].width )
+				{					
+					return i;
+				} 
+			}
+			return -1;
+		}
+		
+		override public function addItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+		
+		override public function removeItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}		
+		
+		override public function replaceItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+		
+		override public function updateItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+		
+		override public function resetItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+				
+		override public function refreshItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+		
+		override public function moveItem( event : CollectionEvent ) : void
+		{
+			//do nothing on move. This shouldn't have an influence on the component.
+		}			
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/HorizontalLinesLayoutItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/HorizontalLinesLayoutItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/HorizontalLinesLayoutItem.as	(revision 15)
@@ -0,0 +1,45 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+
+	/**
+	 * @private
+	 */	
+	public class HorizontalLinesLayoutItem
+	{		
+		public var width : Number;
+		public var height : Number;
+		public var x : Number;
+		public var y : Number;		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayoutProvider.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayoutProvider.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayoutProvider.as	(revision 15)
@@ -0,0 +1,40 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import flash.events.IEventDispatcher;
+
+	public interface ILayoutProvider extends ILayout
+	{
+		function update() : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/VerticalLinesLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/VerticalLinesLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/VerticalLinesLayout.as	(revision 15)
@@ -0,0 +1,143 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import gssim.gssimstudio.editor.charts.scheduling.timelineClasses.ITimeDescriptor;
+	import gssim.gssimstudio.editor.charts.scheduling.timelineClasses.TimeRangeDescriptorUtil;
+	
+	import mx.collections.ArrayCollection;
+	import mx.collections.IList;
+	
+	[Event(name="update",type="charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent")]
+	public class VerticalLinesLayout extends Layout implements IVerticalLinesLayout
+	{
+		private var _minimumTimeRangeWidth : Number = 80;
+		private var _timeRanges : IList;
+
+		private var _contentWidth : Number;
+		
+		public function VerticalLinesLayout()
+		{
+			timeRanges = TimeRangeDescriptorUtil.getDefaultTimeRangeDescriptor();
+		}
+		
+		public function get timeRanges() : IList
+		{
+			return _timeRanges;
+		}		
+		
+		public function set timeRanges( value : IList ) : void
+		{
+			_timeRanges = value;
+		}		
+		
+		public function get minimumTimeRangeWidth() : Number
+		{
+			return _minimumTimeRangeWidth;
+		}
+		
+		public function set minimumTimeRangeWidth( value : Number ) : void
+		{
+			_minimumTimeRangeWidth = value;
+		}
+		
+		override public function get contentWidth() : Number 
+		{
+			return _contentWidth;
+		}
+		
+		override public function set contentWidth( value : Number ) : void
+		{
+			xPosition *= value / _contentWidth; 
+			_contentWidth = value;
+		}
+			
+		public function update( event : LayoutUpdateEvent ) : void
+		{
+			entryLayout = IEntryLayout( event.layout );
+			contentWidth = entryLayout.contentWidth;
+			startDate = entryLayout.startDate;
+			endDate = entryLayout.endDate;			
+			viewportWidth = entryLayout.viewportWidth;
+			viewportHeight = entryLayout.viewportHeight;
+			xPosition = entryLayout.xPosition;
+			yPosition = entryLayout.yPosition;
+			
+			calculateItems( entryLayout ); 
+			dispatchEvent( new LayoutUpdateEvent( this ) );
+		}
+		
+		protected function calculateItems( entryLayout : IEntryLayout ) : void
+		{
+			var timeDescriptor : ITimeDescriptor = getTimeDescriptor( contentWidth, totalMilliseconds );	
+			var millisecondsPerColumn : Number = timeDescriptor.date.getTime();
+			//var numberOfItems : Number = Math.floor( totalMilliseconds / millisecondsPerColumn ) + 1;
+			var numberOfItems : Number = totalMilliseconds / millisecondsPerColumn;
+			var columnWidth : Number = contentWidth / numberOfItems;
+			if( columnWidth < minimumTimeRangeWidth ) columnWidth = minimumTimeRangeWidth;
+			
+			_items = new ArrayCollection();
+			var firstIndex : Number = Math.floor( xPosition / columnWidth );
+			var lastIndex : Number = Math.ceil(( xPosition + viewportWidth ) / columnWidth );
+			
+			for( var i : Number = firstIndex; i < lastIndex; i++ )
+			{
+				var item : VerticalLinesLayoutItem = new VerticalLinesLayoutItem();
+				
+				item.height = viewportHeight;
+				item.x = i * columnWidth;
+				item.y = 0;
+				
+				_items.addItem( item );
+			}
+		}
+		
+		/**
+		 * try to find the smallest unit, which is wider than the minimumTimeRangeWidth
+		 */
+		private function getTimeDescriptor( totalWidth : Number, totalMilliseconds : Number ) : ITimeDescriptor
+		{
+			var length : Number = timeRanges.length;
+			for( var i : Number = 0; i < length; i++ )
+			{
+				var entry : ITimeDescriptor = ITimeDescriptor( timeRanges.getItemAt( i ) );
+				var step : Number = entry.date.getTime();
+				var width : Number = step / totalMilliseconds * totalWidth;
+				if( width >= minimumTimeRangeWidth )
+				{
+					return entry;
+				}
+			}
+			return ITimeDescriptor( timeRanges.getItemAt( length - 1 ) );
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IEntryLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IEntryLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IEntryLayout.as	(revision 15)
@@ -0,0 +1,58 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+	
+	import flash.events.IEventDispatcher;
+	
+	import mx.collections.IList;
+	import mx.events.CollectionEvent;
+
+	public interface IEntryLayout extends ILayoutProvider
+	{
+		function get dataProvider() : IList;
+		function set dataProvider( value : IList ) : void;
+		function get rowHeight() : Number;
+		function set rowHeight( value : Number ) : void;
+		function findLayoutItem( entry : IScheduleEntry ) : EntryLayoutItem;
+		
+		function createLayout() : void;				
+		function addItem( event : CollectionEvent ) : void;
+		function removeItem( event : CollectionEvent ) : void;
+		function replaceItem( event : CollectionEvent ) : void;
+		function updateItem( event : CollectionEvent ) : void;
+		function resetItem( event : CollectionEvent ) : void;
+		function refreshItem( event : CollectionEvent ) : void;
+		function moveItem( event : CollectionEvent ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IVerticalLinesLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IVerticalLinesLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IVerticalLinesLayout.as	(revision 15)
@@ -0,0 +1,45 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import flash.events.IEventDispatcher;
+	
+	import mx.collections.IList;
+
+	public interface IVerticalLinesLayout extends ILayoutClient
+	{
+		function get minimumTimeRangeWidth() : Number;
+		function set minimumTimeRangeWidth( value : Number ) : void;
+		function get timeRanges() : IList;
+		function set timeRanges( value : IList ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BackgroundLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BackgroundLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/BackgroundLayout.as	(revision 15)
@@ -0,0 +1,182 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.BackgroundItem;
+	import gssim.gssimstudio.editor.charts.scheduling.timelineClasses.ITimeDescriptor;
+	import gssim.gssimstudio.editor.charts.scheduling.timelineClasses.TimeRangeDescriptorUtil;
+	
+	import mx.collections.ArrayCollection;
+	import mx.collections.IList;
+	
+	[Event(name="update",type="charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent")]
+	public class BackgroundLayout extends Layout implements IBackgroundLayout
+	{		
+		private var _minimumTimeRangeWidth : Number = 80;
+		private var _backgroundItems : IList;
+		private var _timeRanges : IList;			
+		
+		private var _contentWidth : Number;	
+		
+		public function BackgroundLayout()
+		{
+			timeRanges = TimeRangeDescriptorUtil.getDefaultTimeRangeDescriptor();
+		}
+				
+		public function get minimumTimeRangeWidth() : Number
+		{
+			return _minimumTimeRangeWidth;
+		}
+		
+		public function set minimumTimeRangeWidth( value : Number ) : void
+		{
+			_minimumTimeRangeWidth = value;
+		}
+		
+		public function get backgroundItems() : IList
+		{
+			return _backgroundItems;
+		}
+		
+		public function set backgroundItems( value : IList ) : void
+		{
+			_backgroundItems = value;
+		}
+		
+		override public function get contentWidth() : Number
+		{
+			return _contentWidth;
+		}
+		
+		override public function set contentWidth( value : Number ) : void
+		{
+			xPosition *= value / _contentWidth; 
+			_contentWidth = value;
+		}
+		
+		public function get timeRanges() : IList
+		{
+			return _timeRanges;
+		}		
+		
+		public function set timeRanges( value : IList ) : void
+		{
+			_timeRanges = value;
+		}
+		
+		public function update( event : LayoutUpdateEvent ) : void
+		{
+			entryLayout = IEntryLayout( event.layout );
+			contentWidth = entryLayout.contentWidth;
+			startDate = entryLayout.startDate;
+			endDate = entryLayout.endDate;
+			viewportWidth = entryLayout.viewportWidth;
+			viewportHeight = entryLayout.viewportHeight;			
+			xPosition = entryLayout.xPosition;
+			yPosition = entryLayout.yPosition;			
+			
+			calculateItems();
+			dispatchEvent( new LayoutUpdateEvent( this ) );
+		}
+		
+		private function calculateItems() : void
+		{
+			var timeDescriptor : ITimeDescriptor = getTimeDescriptor( contentWidth, totalMilliseconds );
+			var millisecondsPerColumn : Number = timeDescriptor.date.getTime();	
+			var numberOfItems : Number = Math.floor( totalMilliseconds / millisecondsPerColumn ) + 1;
+			var columnWidth : Number = contentWidth / numberOfItems;
+			if( columnWidth < minimumTimeRangeWidth ) columnWidth = minimumTimeRangeWidth;
+			
+			_items = new ArrayCollection();
+			var firstIndex : Number = Math.floor( xPosition / columnWidth );
+			var lastIndex : Number = Math.ceil(( xPosition + viewportWidth ) / columnWidth );
+			
+			for( var i : Number = firstIndex; i < lastIndex; i++ )
+			{
+				var item : BackgroundLayoutItem = new BackgroundLayoutItem();
+				
+				item.width = columnWidth;
+				item.height = viewportHeight;
+				item.x = i * columnWidth;
+				
+				var currentTime : Number = ( i * columnWidth + columnWidth / 2 ) * totalMilliseconds / contentWidth;
+				var colorItem : BackgroundItem = findBackgroundItem( currentTime );
+				if( colorItem == null ) continue;
+				item.backgroundColor = colorItem.color;
+				item.toolTip = colorItem.description;
+				
+				var now : Number = new Date().getTime() - _startDate;
+				var currentIndex : Number = Math.floor( now / columnWidth );
+				if( i == currentIndex ) item.backgroundColor = 0xff0000;
+	
+				_items.addItem( item );
+			}
+		}
+		
+		/**
+		 * try to find the smallest unit, which is wider than the minimumTimeRangeWidth
+		 */
+		private function getTimeDescriptor( totalWidth : Number, totalMilliseconds : Number ) : ITimeDescriptor
+		{
+			var length : Number = timeRanges.length;
+			for( var i : Number = 0; i < length; i++ )
+			{
+				var entry : ITimeDescriptor = ITimeDescriptor( timeRanges.getItemAt( i ) );
+				var step : Number = entry.date.getTime();
+				var width : Number = step / totalMilliseconds * totalWidth;
+				if( width >= minimumTimeRangeWidth )
+				{
+					return entry;
+				}
+			}
+			return ITimeDescriptor( timeRanges.getItemAt( length - 1 ) );
+		}
+		
+		/**
+		 * return background definition depending on time
+		 */ 
+		private function findBackgroundItem( relativeTime : Number ) : BackgroundItem
+		{
+			if( _backgroundItems == null ) return null;
+			var result : BackgroundItem = null;			
+			for( var i : Number = 0; i < _backgroundItems.length; i++ )
+			{
+				var colorItem : BackgroundItem = BackgroundItem( _backgroundItems.getItemAt( i ) );
+				if( relativeTime >= colorItem.startDate.getTime() && relativeTime < colorItem.endDate.getTime() )
+				{
+					result = colorItem;
+				}
+			}			
+			return result;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/Layout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/Layout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/Layout.as	(revision 15)
@@ -0,0 +1,154 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import flash.events.EventDispatcher;
+	
+	import mx.collections.ArrayCollection;
+	import mx.collections.IList;
+
+	public class Layout extends EventDispatcher implements ILayout
+	{
+		protected var _items : IList;
+		protected var _startDate : Number;
+		protected var _endDate : Number;	
+		private var _entryLayout : IEntryLayout;	
+		private var _contentWidth : Number;
+		private var _contentHeight : Number;
+		private var _viewportWidth : Number;
+		private var _viewportHeight : Number;
+		private var _xPosition : Number = 0;
+		private var _yPosition : Number = 0;		
+		
+		public function get entryLayout() : IEntryLayout
+		{
+		    return _entryLayout;
+		}
+		
+		public function set entryLayout( value : IEntryLayout ) : void
+		{
+			_entryLayout = value;
+		}
+		
+		public function get items() : IList
+		{
+		    return _items;
+		}
+				
+		public function get contentWidth() : Number
+		{
+		    return _contentWidth;
+		}
+		
+		public function set contentWidth( value : Number ) : void
+		{
+			_contentWidth = value;
+		}
+
+		public function get contentHeight() : Number
+		{
+		    return _contentHeight;
+		}
+		
+		public function set contentHeight( value : Number ) : void
+		{
+			_contentHeight = value;
+		}		
+			
+		public function get viewportWidth() : Number
+		{
+		    return _viewportWidth;
+		}
+		
+		public function set viewportWidth( value : Number ) : void
+		{
+			_viewportWidth = value;
+		}
+		
+		public function get viewportHeight() : Number
+		{
+		    return _viewportHeight;
+		}
+		
+		public function set viewportHeight( value : Number ) : void
+		{
+			_viewportHeight = value;
+		}
+				
+		public function get startDate() : Date
+		{
+			return new Date( _startDate );
+		}
+		
+		public function set startDate( value : Date ) : void
+		{
+			_startDate = value.getTime();
+		}
+		
+		public function get endDate() : Date
+		{
+			return new Date( _endDate );
+		}
+		
+		public function set endDate( value : Date ) : void
+		{
+			_endDate = value.getTime();
+		}
+		
+		public function get totalMilliseconds() : Number
+		{
+			return _endDate - _startDate;
+		}		
+		
+		[Bindable]
+		public function get xPosition() : Number
+		{
+			return _xPosition;
+		}
+		
+		public function set xPosition( value : Number ) : void
+		{
+			if( isNaN( value )) return;
+			_xPosition = value;
+		}
+		
+		public function get yPosition() : Number
+		{
+			return _yPosition;
+		}
+		
+		public function set yPosition( value : Number ) : void
+		{
+			_yPosition = value;
+		}		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/EntryLayoutItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/EntryLayoutItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/EntryLayoutItem.as	(revision 15)
@@ -0,0 +1,62 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+
+	public class EntryLayoutItem
+	{
+		//content
+		public var data : IScheduleEntry;
+		
+		//layoutData
+		public var x : Number;
+		public var y : Number;
+		public var width : Number;
+		public var height : Number;
+		
+		public var row : Number;
+		public var zoom : Number;
+		
+		public function toString() : String
+		{
+			return "[object EntryLayoutItem"
+			  + " row:" + row 
+			  + " x:" + x 
+			  + " y:" + y 
+			  + " width:" + width 
+			  + " height:" + height 
+			  + "]";
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/VerticalLinesLayoutItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/VerticalLinesLayoutItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/VerticalLinesLayoutItem.as	(revision 15)
@@ -0,0 +1,44 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	/**
+	 * @private
+	 */
+	public class VerticalLinesLayoutItem
+	{
+		public var width : Number;
+		public var height : Number;
+		public var x : Number;
+		public var y : Number;		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/LayoutUpdateEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/LayoutUpdateEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/LayoutUpdateEvent.as	(revision 15)
@@ -0,0 +1,52 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import flash.events.Event;
+	
+	public class LayoutUpdateEvent extends Event
+	{
+		public static var UPDATE : String = "update";
+		public var layout : ILayout;
+		
+		public function LayoutUpdateEvent( layout : ILayout )
+		{
+			super( LayoutUpdateEvent.UPDATE );
+			this.layout = layout;
+		}
+		
+		override public function clone() : Event
+		{
+			return new LayoutUpdateEvent( layout );
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/HorizontalLinesLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/HorizontalLinesLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/HorizontalLinesLayout.as	(revision 15)
@@ -0,0 +1,87 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import mx.collections.ArrayCollection;
+	import mx.collections.IList;
+	
+	[Event(name="update",type="charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent")]
+	public class HorizontalLinesLayout extends Layout implements IHorizontalLinesLayout
+	{
+		private var _rowHeight : Number;
+	
+		public function get rowHeight() : Number
+		{
+		    return _rowHeight;
+		}
+		
+		public function set rowHeight( value : Number ) : void
+		{
+			_rowHeight = value;
+		}
+		
+		public function update( event : LayoutUpdateEvent ) : void
+		{
+			entryLayout = IEntryLayout( event.layout );
+			contentWidth = entryLayout.contentWidth;
+			startDate = entryLayout.startDate;
+			endDate = entryLayout.endDate;			
+			viewportWidth = entryLayout.viewportWidth;
+			viewportHeight = entryLayout.viewportHeight;
+			rowHeight = entryLayout.rowHeight;
+			xPosition = entryLayout.xPosition;
+			yPosition = entryLayout.yPosition;
+			
+			calculateItems( entryLayout );
+			dispatchEvent( new LayoutUpdateEvent( this ) );
+		}
+		
+		protected function calculateItems( entryLayout : IEntryLayout ) : void
+		{
+			var result : IList = new ArrayCollection();
+			var firstRow : Number = Math.floor( yPosition / rowHeight );
+			var lastRow : Number = Math.ceil(( yPosition + viewportHeight ) / rowHeight );
+	      
+			for( var i : Number = firstRow; i <= lastRow; i++ )
+			{
+				var item : HorizontalLinesLayoutItem = new HorizontalLinesLayoutItem();
+				
+				item.x = 0;
+				item.y = i * rowHeight;
+				item.width = viewportWidth;
+				
+				result.addItem( item );
+			}
+			_items = result;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/AbstractEntryLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/AbstractEntryLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/AbstractEntryLayout.as	(revision 15)
@@ -0,0 +1,259 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.RowLocatorItem;
+	
+	import flash.utils.Dictionary;
+	
+	import mx.collections.ArrayCollection;
+	import mx.collections.IList;
+	import mx.events.CollectionEvent;
+	
+	[Event(name="update",type="charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent")]
+	public class AbstractEntryLayout extends Layout implements IEntryLayout
+	{
+		protected var rows : Array;
+		private var rowLocator : Dictionary;		
+		private var _dataProvider : IList;	
+		private var _xPosition : Number = 0;	
+		private var _rowHeight : Number = 50;
+		
+		public function AbstractEntryLayout()
+		{
+			createLayout();
+		}
+		
+		public function get dataProvider() : IList
+		{
+		    return _dataProvider;
+		}
+		
+		public function set dataProvider( value : IList ) : void
+		{
+			_dataProvider = value;
+			//tryToCreateLayout();
+		}
+				
+		override public function get xPosition() : Number
+		{
+			var zoom : Number = totalMilliseconds / contentWidth;
+			
+			return _xPosition / zoom;
+		}		
+		
+		override public function set xPosition( value : Number ) : void
+		{
+			if( isNaN( value )) return;
+			
+			var zoom : Number = totalMilliseconds / contentWidth;
+			
+			_xPosition = value * zoom;
+		}
+		
+		[Bindable]
+		public function get rowHeight() : Number
+		{
+		    return _rowHeight;
+		}
+		
+		public function set rowHeight( value : Number ) : void
+		{
+			_rowHeight = value;
+		}
+		
+		
+		
+		
+		
+		
+		
+		public function findLayoutItem( entry : IScheduleEntry ) : EntryLayoutItem
+		{
+			var rowLocatorItem : RowLocatorItem = getRowLocatorItem( entry );
+			if( rowLocatorItem != null )
+			{
+				if( rowLocatorItem.layoutItem != null )
+				{
+					return rowLocatorItem.layoutItem;
+				}
+			}
+			return null;
+		}
+				
+		public function update() : void
+		{
+			calculateItems();
+			dispatchEvent( new LayoutUpdateEvent( this ) );
+		}
+		
+		
+		public function createLayout() : void
+		{
+			rows = new Array();
+			rowLocator = new Dictionary( true );
+		}
+				
+		public function setRowLocatorItem( item : EntryLayoutItem, rowLocatorItem : RowLocatorItem ) : void
+		{
+			rowLocatorItem.layoutItem = item;
+			rowLocator[ item.data ] = rowLocatorItem;
+		}
+		
+		public function getRowLocatorItem( entry : IScheduleEntry ) : RowLocatorItem
+		{
+			return rowLocator[ entry ];
+		}
+		
+		public function deleteRowLocatorItem( entry : IScheduleEntry ) : RowLocatorItem
+		{
+			return rowLocator[ entry ] = null;
+		}
+		
+		protected function saveItemWithRow( item : EntryLayoutItem, row : Number, rowItem : Number ) : void
+		{
+			var rowLocatorItem : RowLocatorItem = new RowLocatorItem();
+			rowLocatorItem.row = row;
+			rowLocatorItem.rowItem = rowItem;
+			setRowLocatorItem( item, rowLocatorItem );
+		}			
+			
+		protected function isOffScreenLeftRight( entryStart : Number, viewPortEnd : Number ) : Boolean
+ 		{
+  			var isOff : Boolean;
+  			var isOffScreenOnLeftSide : Boolean = ( entryStart < 0 );
+ 			var isOffScreenOnRightSide : Boolean = ( entryStart > viewPortEnd );	 			
+ 			if( isOffScreenOnLeftSide || isOffScreenOnRightSide )
+ 			{
+ 				isOff = true;
+ 			}
+ 			return isOff;
+ 		}
+		
+ 		protected function isTooSmall( width : Number ) : Boolean
+ 		{
+ 			var tooSmall : Boolean = ( width <= 0 );
+ 			if( tooSmall )
+ 			{
+ 				//optionally you could use a default width
+ 			}
+ 			return tooSmall;
+ 		}
+ 		
+ 		protected function updateLayouterProperties() : void
+		{
+			contentHeight = rows.length * rowHeight;
+		}
+				
+		/**
+		 * Potentially expensive call!
+		 */		
+		private function tryToCreateLayout() : void
+		{
+			if( dataProvider != null && startDate != null && endDate != null && !isNaN( rowHeight ) )
+			{
+				createLayout();
+			}
+		}
+		
+		/**
+		 * find the items which are currently visible in the viewport
+		 * _xPosition is an unscaled value 
+		 * 
+		 * TODO: If rows were ordered by x, we could optimize the search for items
+		 */ 
+		private function calculateItems() : void
+		{
+			var result : ArrayCollection = new ArrayCollection();
+			var firstRow : Number = Math.floor( yPosition / rowHeight );
+			var lastRow : Number = Math.ceil(( yPosition + viewportHeight ) / rowHeight );
+			if( lastRow >= rows.length ) lastRow = rows.length - 1;
+			
+			var totalMilliseconds : Number = endDate.getTime() - startDate.getTime();
+			var zoom : Number = totalMilliseconds / contentWidth;
+			
+			var xStart : Number = _xPosition;
+			var xEnd : Number = _xPosition + viewportWidth * zoom;
+			
+			for( var rowIndex : Number = firstRow; rowIndex <= lastRow; rowIndex++ )
+			{
+				var row : Array = rows[ rowIndex ];
+				for each( var item : EntryLayoutItem in row )
+				{
+					if( item.x < xEnd && item.x + item.width >= xStart ) 
+					{
+						item.zoom = zoom;
+						item.row = rowIndex;
+						result.addItem( item );					
+					}
+				}	
+			}
+			_items = result;
+		}
+		
+		public function addItem( event : CollectionEvent ) : void
+		{
+			throw new Error( "Abstract method invoked" );
+		}
+		
+		public function removeItem( event : CollectionEvent ) : void
+		{
+			throw new Error( "Abstract method invoked" );
+		}		
+		
+		public function replaceItem( event : CollectionEvent ) : void
+		{
+			throw new Error( "Abstract method invoked" );
+		}
+		
+		public function updateItem( event : CollectionEvent ) : void
+		{
+			throw new Error( "Abstract method invoked" );
+		}
+		
+		public function resetItem( event : CollectionEvent ) : void
+		{
+			throw new Error( "Abstract method invoked" );
+		}
+				
+		public function refreshItem( event : CollectionEvent ) : void
+		{
+			throw new Error( "Abstract method invoked" );
+		}
+		
+		public function moveItem( event : CollectionEvent ) : void
+		{
+			throw new Error( "Abstract method invoked" );
+		}		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayoutClient.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayoutClient.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayoutClient.as	(revision 15)
@@ -0,0 +1,40 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import flash.events.IEventDispatcher;
+
+	public interface ILayoutClient extends ILayout
+	{
+		function update( event : LayoutUpdateEvent ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IBackgroundLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IBackgroundLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IBackgroundLayout.as	(revision 15)
@@ -0,0 +1,45 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import mx.collections.IList;
+
+	public interface IBackgroundLayout extends ILayoutClient
+	{
+		function get backgroundItems() : IList;
+		function set backgroundItems( value : IList ) : void;
+		function get minimumTimeRangeWidth() : Number;
+		function set minimumTimeRangeWidth( value : Number ) : void;
+		function get timeRanges() : IList;
+		function set timeRanges( value : IList ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/ILayout.as	(revision 15)
@@ -0,0 +1,61 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import flash.events.IEventDispatcher;
+	
+	import mx.collections.IList;
+	
+	public interface ILayout extends IEventDispatcher
+	{
+		function get entryLayout() : IEntryLayout;
+		function set entryLayout( value : IEntryLayout ) : void;		
+		function get items() : IList;
+		function get contentWidth() : Number;
+		function set contentWidth( value : Number ) : void;
+		function get contentHeight() : Number;
+		function set contentHeight( value : Number ) : void;
+		function get viewportWidth() : Number;
+		function set viewportWidth( value : Number ) : void;
+		function get viewportHeight() : Number;
+		function set viewportHeight( value : Number ) : void;
+		function get startDate() : Date;
+		function set startDate( value : Date ) : void;
+		function get endDate() : Date;
+		function set endDate( value : Date ) : void;
+		function get totalMilliseconds() : Number;	
+		function get xPosition() : Number;
+		function set xPosition( value : Number ) : void;
+		function get yPosition() : Number;
+		function set yPosition( value : Number ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/SimpleLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/SimpleLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/SimpleLayout.as	(revision 15)
@@ -0,0 +1,120 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+	
+	import mx.collections.IList;
+	import mx.events.CollectionEvent;
+	
+	public class SimpleLayout extends AbstractEntryLayout implements IEntryLayout
+	{		
+		override public function createLayout() : void
+		{
+			super.createLayout();
+			if( dataProvider == null ) return;
+			createLayoutFor( 0, dataProvider.length );
+		}
+		
+		private function createLayoutFor( startIndex : Number, endIndex : Number ) : void
+		{
+			var len : Number = endIndex;
+			for( var i : Number = startIndex; i < len; i++ )
+			{
+				var rowItems : IList = IList( dataProvider.getItemAt( i ) );
+				addRowItemsToRow( rowItems, i );
+			}
+			updateLayouterProperties();
+		}		
+		
+		private function addRowItemsToRow( rowItems : IList, i : Number ) : void
+		{
+			rows[ i ] = new Array();
+			var rowItemsLength : Number = 	rowItems.length;
+			for ( var j : Number = 0; j < rowItemsLength; j++ )
+			{
+				var item : IScheduleEntry = IScheduleEntry( rowItems.getItemAt( j ) );
+				
+				var x : Number = item.startDate.getTime() - startDate.getTime();					
+				if( isOffScreenLeftRight( x, totalMilliseconds ) ) continue;
+				
+				var width : Number = item.endDate.getTime() - item.startDate.getTime();
+				if( isTooSmall( width ) ) continue;
+				
+				var layoutItem : EntryLayoutItem = new EntryLayoutItem();
+				layoutItem.x = x;
+				layoutItem.y = i * rowHeight;	
+				layoutItem.width = width; 
+				layoutItem.height = rowHeight;
+				layoutItem.data = item;
+				
+				rows[ i ][ j ] = layoutItem;
+				saveItemWithRow( layoutItem, i, j );
+			}
+		}
+		
+		override public function addItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+		
+		override public function removeItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}		
+		
+		override public function replaceItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+		
+		override public function updateItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+		
+		override public function resetItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+				
+		override public function refreshItem( event : CollectionEvent ) : void
+		{
+			createLayout();
+		}
+		
+		override public function moveItem( event : CollectionEvent ) : void
+		{
+			//do nothing on move. This shouldn't have an influence on the component.
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IHorizontalLinesLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IHorizontalLinesLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/layout/IHorizontalLinesLayout.as	(revision 15)
@@ -0,0 +1,41 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout
+{
+	import flash.events.IEventDispatcher;
+	
+	public interface IHorizontalLinesLayout extends ILayoutClient
+	{
+		function get rowHeight() : Number;
+		function set rowHeight( value : Number ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/Schedule.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/Schedule.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/Schedule.as	(revision 15)
@@ -0,0 +1,358 @@
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{
+   import gssim.gssimstudio.editor.charts.scheduling.ScheduleViewer;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.AbstractEntryLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.BackgroundLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.BestFitLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.HorizontalLinesLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IBackgroundLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IEntryLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IHorizontalLinesLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IVerticalLinesLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.VerticalLinesLayout;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers.IScheduleEntryRenderer;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers.BackgroundViewer;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers.EntryViewer;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers.HorizontalLinesViewer;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers.IHorizontalLinesViewer;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers.IVerticalLinesViewer;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers.VerticalLinesViewer;
+   
+   import mx.collections.ArrayCollection;
+   import mx.collections.IList;
+   import mx.core.ClassFactory;
+   import mx.core.IFactory;
+   import mx.core.UIComponent;
+ 	
+   public class Schedule
+   {      
+      public var isViewlayersInitialized : Boolean;
+      public var navigator : ScheduleNavigator;
+      
+      public var backgroundLayoutImpl : IBackgroundLayout;
+      public var horizontalLinesLayoutImpl : IHorizontalLinesLayout;
+      public var verticalLinesLayoutImpl : IVerticalLinesLayout;
+      public var horizontalLinesViewerImpl : IHorizontalLinesViewer;
+      public var verticalLinesViewerImpl : IVerticalLinesViewer;
+      
+  		public var entryViewer : EntryViewer;
+		public var backgroundViewer : BackgroundViewer;
+		
+		public var content : UIComponent;
+		    
+      private var owner : ScheduleViewer; 		
+		private var _entryLayoutImpl : IEntryLayout;
+		
+		private var _entryLayout : IFactory;		
+		private var _backgroundLayout : IFactory;		
+		private var _horizontalLinesLayout : IFactory;		
+		private var _verticalLinesLayout : IFactory;     
+            
+		private var _horizontalLinesViewer : IFactory;		
+		private var _verticalLinesViewer : IFactory;		     
+      
+      public function Schedule( owner : ScheduleViewer )
+      {
+         this.owner = owner;
+      }
+      
+      public function initialize() : void
+      {
+         isViewlayersInitialized = false;
+         createEntryLayout();
+         createEntryViewer();
+         createBackgroundLayout();
+         createHorizontalLinesLayout();
+         createHorizontalLinesViewer();
+         createVerticalLinesLayout();
+         createVerticalLinesViewer();
+      }
+      
+		public function initializeCompileTimeViewLayers() : void
+		{
+			backgroundViewer = new BackgroundViewer();			
+			createEntryViewer();
+		}
+				
+		public function initializeRuntimeViewLayers() : void
+		{
+			createEntryLayout();
+			createBackgroundLayout();
+			createHorizontalLinesLayout();
+			createHorizontalLinesViewer();
+			createVerticalLinesLayout();
+			createVerticalLinesViewer();
+			
+			entryLayoutImpl.addEventListener( LayoutUpdateEvent.UPDATE, entryViewer.update );
+			backgroundLayoutImpl.addEventListener( LayoutUpdateEvent.UPDATE, backgroundViewer.update );
+			horizontalLinesLayoutImpl.addEventListener( LayoutUpdateEvent.UPDATE, horizontalLinesViewerImpl.update );
+			verticalLinesLayoutImpl.addEventListener( LayoutUpdateEvent.UPDATE, verticalLinesViewerImpl.update );
+			
+			entryLayoutImpl.addEventListener( LayoutUpdateEvent.UPDATE, backgroundLayoutImpl.update );
+			entryLayoutImpl.addEventListener( LayoutUpdateEvent.UPDATE, horizontalLinesLayoutImpl.update );
+			entryLayoutImpl.addEventListener( LayoutUpdateEvent.UPDATE, verticalLinesLayoutImpl.update );
+
+			initializeViewLayerProperties();
+		}
+		
+		[Bindable]
+		public function get entryLayout() : IFactory 
+		{
+			return _entryLayout;
+		}
+				
+		public function set entryLayout( value : IFactory ) : void
+		{
+			if( value != null && value != _entryLayout )
+			{
+				_entryLayout = value;				
+			}
+		}
+		
+		[Bindable]
+		public function get entryRenderer() : IFactory 
+		{
+			return entryViewer.entryRenderer;
+		}
+				
+		public function set entryRenderer( value : IFactory ) : void
+		{
+			if( value != null && value != entryViewer.entryRenderer )
+			{
+				entryViewer.entryRenderer = value;	
+			}
+		}
+		
+		[Bindable]
+		public function get backgroundLayout() : IFactory 
+		{
+			return _backgroundLayout;
+		}
+			
+		public function set backgroundLayout( value : IFactory ) : void
+		{
+			if( value != null && value != _backgroundLayout )
+			{
+				_backgroundLayout = value;				
+			}
+		}
+				
+		[Bindable]
+		public function get horizontalLinesLayout() : IFactory 
+		{
+			return _horizontalLinesLayout;
+		}
+			
+		public function set horizontalLinesLayout( value : IFactory ) : void
+		{
+			if( value != null && value != _horizontalLinesLayout )
+			{
+				_horizontalLinesLayout = value;				
+			}
+		}
+		
+		[Bindable]
+		public function get horizontalLinesViewer() : IFactory 
+		{
+			return _horizontalLinesViewer;
+		}
+			
+		public function set horizontalLinesViewer( value : IFactory ) : void
+		{
+			if( value != null && value != _horizontalLinesViewer )
+			{
+				_horizontalLinesViewer = value;				
+			}
+		}
+		
+		[Bindable]
+		public function get verticalLinesLayout() : IFactory 
+		{
+			return _verticalLinesLayout;
+		}
+		
+		public function set verticalLinesLayout( value : IFactory ) : void
+		{
+			if( value != null && value != _verticalLinesLayout )
+			{
+				_verticalLinesLayout = value;				
+			}
+		}
+		
+		[Bindable]
+		public function get verticalLinesViewer() : IFactory 
+		{
+			return _verticalLinesViewer;
+		}
+			
+		public function set verticalLinesViewer( value : IFactory ) : void
+		{
+			if( value != null && value != _verticalLinesViewer )
+			{
+				_verticalLinesViewer = value;				
+			}
+		}
+		
+		public function get entryLayoutImpl() : IEntryLayout 
+		{
+			return _entryLayoutImpl;
+		}
+				
+		public function set entryLayoutImpl( value : IEntryLayout ) : void
+		{
+			navigator.entryLayoutImpl = value;
+			_entryLayoutImpl = value;
+		}
+		
+		
+				
+		
+		
+		
+				
+		
+		private function createEntryLayout() : void
+		{
+			if( _entryLayout == null )
+			{
+				entryLayout = new ClassFactory( BestFitLayout );
+				entryLayoutImpl = IEntryLayout( _entryLayout.newInstance() );
+			}
+			else
+			{
+				var contentWidth : Number = entryLayoutImpl.contentWidth;
+				var contentHeight : Number = entryLayoutImpl.contentHeight;
+				var startDate : Date = entryLayoutImpl.startDate;
+				var endDate : Date = entryLayoutImpl.endDate;
+				var rowHeight : Number = entryLayoutImpl.rowHeight;
+				
+				entryLayoutImpl = IEntryLayout( _entryLayout.newInstance() );
+				entryLayoutImpl.contentWidth = contentWidth;
+				entryLayoutImpl.contentHeight = contentHeight;
+				entryLayoutImpl.startDate = startDate;
+				entryLayoutImpl.endDate = endDate;
+				entryLayoutImpl.rowHeight = rowHeight;				
+			}
+		}
+		
+		private function createEntryViewer() : void
+		{
+			if( entryViewer == null )
+			{
+				entryViewer = new EntryViewer(owner);
+			}
+		}		
+				
+		private function createBackgroundLayout() : void
+		{
+			if( _horizontalLinesLayout == null )
+			{
+				backgroundLayout = new ClassFactory( BackgroundLayout );
+				backgroundLayoutImpl = IBackgroundLayout( _backgroundLayout.newInstance() );
+			}
+			else
+			{
+				var backgroundItems : IList = backgroundLayoutImpl.backgroundItems;
+				var timeRanges : IList = backgroundLayoutImpl.timeRanges
+				var minimumTimeRangeWidth : Number = backgroundLayoutImpl.minimumTimeRangeWidth;
+				
+				backgroundLayoutImpl = IBackgroundLayout( _backgroundLayout.newInstance() );
+				backgroundLayoutImpl.backgroundItems = backgroundItems;
+				backgroundLayoutImpl.timeRanges = timeRanges;
+				backgroundLayoutImpl.minimumTimeRangeWidth = minimumTimeRangeWidth;
+			}
+		}
+						
+		private function createHorizontalLinesLayout() : void
+		{
+			if( _horizontalLinesLayout == null )
+			{
+				horizontalLinesLayout = new ClassFactory( HorizontalLinesLayout );
+				horizontalLinesLayoutImpl = IHorizontalLinesLayout( _horizontalLinesLayout.newInstance() );
+			}
+			else
+			{
+				horizontalLinesLayoutImpl = IHorizontalLinesLayout( _horizontalLinesLayout.newInstance() );
+			}
+		}
+		
+		private function createHorizontalLinesViewer() : void
+		{
+			if( _horizontalLinesViewer == null )
+			{
+				horizontalLinesViewer = new ClassFactory( HorizontalLinesViewer );
+				horizontalLinesViewerImpl = IHorizontalLinesViewer( _horizontalLinesViewer.newInstance() );
+			}
+			else
+			{
+				horizontalLinesViewerImpl = IHorizontalLinesViewer( _horizontalLinesViewer.newInstance() );
+			}
+		}
+		
+		private function createVerticalLinesLayout() : void
+		{
+			if( _verticalLinesLayout == null )
+			{
+				verticalLinesLayout = new ClassFactory( VerticalLinesLayout );
+				verticalLinesLayoutImpl = IVerticalLinesLayout( _verticalLinesLayout.newInstance() );
+			}
+			else
+			{
+				var timeRanges : IList = verticalLinesLayoutImpl.timeRanges
+				var minimumTimeRangeWidth : Number = verticalLinesLayoutImpl.minimumTimeRangeWidth;
+				
+				verticalLinesLayoutImpl = IVerticalLinesLayout( _verticalLinesLayout.newInstance() );
+				verticalLinesLayoutImpl.timeRanges = timeRanges;
+				verticalLinesLayoutImpl.minimumTimeRangeWidth = minimumTimeRangeWidth;
+			}
+		}
+		
+		private function createVerticalLinesViewer() : void
+		{
+			if( _verticalLinesViewer == null )
+			{
+				verticalLinesViewer = new ClassFactory( VerticalLinesViewer );
+				verticalLinesViewerImpl = IVerticalLinesViewer( _verticalLinesViewer.newInstance() );
+			}
+			else
+			{
+				verticalLinesViewerImpl = IVerticalLinesViewer( _verticalLinesViewer.newInstance() );
+			}
+		}		
+		
+		private function initializeViewLayerProperties() : void
+		{
+			if( entryRenderer == null )
+			{
+				entryRenderer = entryViewer.entryRenderer;
+			}
+			else
+			{
+				entryViewer.entryRenderer = entryRenderer;
+			}
+			
+			horizontalLinesViewerImpl.dottedGridLines = owner.getStyle( "dottedGridLines" );
+			horizontalLinesViewerImpl.horizontalGridLineThickness = owner.getStyle( "horizontalGridLineThickness" );
+			horizontalLinesViewerImpl.horizontalGridLineColor = owner.getStyle( "horizontalGridLineColor" );			
+			horizontalLinesViewerImpl.horizontalGridLineAlpha = owner.getStyle( "horizontalGridLineAlpha" );
+			
+			verticalLinesViewerImpl.dottedGridLines = owner.getStyle( "dottedGridLines" );
+			verticalLinesViewerImpl.verticalGridLineThickness = owner.getStyle( "verticalGridLineThickness" );
+			verticalLinesViewerImpl.verticalGridLineColor = owner.getStyle( "verticalGridLineColor" );			
+			verticalLinesViewerImpl.verticalGridLineAlpha = owner.getStyle( "verticalGridLineAlpha" );
+			
+			var entryViewerIndex : int = content.getChildIndex( entryViewer );			
+			content.addChildAt( UIComponent( horizontalLinesViewerImpl ), entryViewerIndex );	
+			content.addChildAt( UIComponent( verticalLinesViewerImpl ), entryViewerIndex );
+		}
+		
+		public function initializeEntryLayout() : void
+		{
+			if( owner.dataProvider != null )
+			{
+				entryLayoutImpl.dataProvider = IList( owner.dataProvider );			
+			}
+		}
+   }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/DottedHorizontalLineRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/DottedHorizontalLineRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/DottedHorizontalLineRenderer.as	(revision 15)
@@ -0,0 +1,64 @@
+/*
+
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+   @ignore
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer
+{
+  import flash.display.Graphics;
+
+  import flash.display.LineScaleMode;
+  import flash.geom.Rectangle;
+
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.utils.GraphicUtils;
+  import flash.display.JointStyle;
+
+
+  /**
+   * @private
+   */
+  public class DottedHorizontalLineRenderer extends Line implements ILineRenderer
+  {
+    public function moveTo(g:Graphics, x:Number, y:Number):void
+    {
+      g.moveTo(x, y);
+    }
+
+    public function drawTo(g:Graphics, x:Number, y:Number):void
+    {
+      GraphicUtils.drawDottedHorizontalLineTo(g, y, 0, x);
+    }
+
+    public function get scaleMode():String
+    {
+      return LineScaleMode.NORMAL;
+    }
+
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/DottedVerticalLineRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/DottedVerticalLineRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/DottedVerticalLineRenderer.as	(revision 15)
@@ -0,0 +1,63 @@
+/*
+
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+   @ignore
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer
+{
+  import flash.display.Graphics;
+
+  import flash.display.LineScaleMode;
+  import flash.geom.Rectangle;
+
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.utils.GraphicUtils;
+  import flash.display.JointStyle;
+  
+
+  /**
+   * @private
+   */
+  public class DottedVerticalLineRenderer extends Line implements ILineRenderer
+  {
+    public function moveTo(g:Graphics, x:Number, y:Number):void
+    {
+      g.moveTo(x, y);
+    }
+
+    public function drawTo(g:Graphics, x:Number, y:Number):void
+    {
+      GraphicUtils.drawDottedVerticalLineTo(g, x, 0, y);
+    }
+
+    public function get scaleMode():String
+    {
+      return LineScaleMode.NORMAL;
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/LineRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/LineRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/LineRenderer.as	(revision 15)
@@ -0,0 +1,63 @@
+/*
+
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+   @ignore
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer
+{
+  import flash.display.Graphics;
+
+  import flash.display.LineScaleMode;
+  import flash.geom.Rectangle;
+  import flash.geom.Point;
+  import flash.display.JointStyle;
+
+  /**
+   * @private
+   */
+  public class LineRenderer extends Line implements ILineRenderer
+  {
+    public function moveTo(g:Graphics, x:Number, y:Number):void
+    {
+      g.moveTo(x, y);
+    }
+
+    public function drawTo(g:Graphics, x:Number, y:Number):void
+    {
+      g.lineTo(x, y);
+    }
+
+    public function get scaleMode():String
+    {
+      return LineScaleMode.NORMAL;
+    }
+
+
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/ILineRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/ILineRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/ILineRenderer.as	(revision 15)
@@ -0,0 +1,51 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer
+{
+	import flash.display.Graphics;
+	
+	import mx.graphics.IStroke;
+	
+	/**
+	 * @private
+	 */	
+	public interface ILineRenderer extends IStroke
+	{
+		function moveTo( g : Graphics, x : Number, y : Number ) : void
+		function drawTo( g : Graphics, x : Number, y : Number ) : void
+		
+		function get color() : uint;
+		function set color( value : uint ) : void;
+		function get alpha() : Number;
+		function set alpha( value : Number ) : void;		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/Line.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/Line.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/lineRenderer/Line.as	(revision 15)
@@ -0,0 +1,68 @@
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer
+{
+  import flash.display.Graphics;
+  import flash.display.GraphicsStroke;
+  import flash.geom.Point;
+  import flash.geom.Rectangle;
+
+  public class Line
+  {
+    private var _weight:Number;
+    private var _color:uint;
+    private var _alpha:Number;
+
+    public function get weight():Number
+    {
+      return _weight;
+    }
+
+    public function set weight(value:Number):void
+    {
+      _weight = value;
+    }
+
+    public function get color():uint
+    {
+      return _color;
+    }
+
+    public function set color(value:uint):void
+    {
+      _color = value;
+    }
+
+    public function get alpha():Number
+    {
+      return _alpha;
+    }
+
+    public function set alpha(value:Number):void
+    {
+      _alpha = value;
+    }
+
+	/**********
+	 * Flex 4 *
+	 **********/
+	
+	public function apply(g:Graphics, bounds : Rectangle, origin : Point):void
+	{
+		g.lineStyle(weight, color, alpha);
+	}
+	
+	public function createGraphicsStroke(bounds : Rectangle, origin : Point) : GraphicsStroke
+	{
+		return null;
+	}
+	
+	public function get miterLimit() : Number
+	{
+		return 3.0;
+	}
+	
+	public function get joints() : String
+	{
+		return null;
+	}
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/BackgroundItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/BackgroundItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/BackgroundItem.as	(revision 15)
@@ -0,0 +1,40 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{
+	public class BackgroundItem
+	{
+		public var color : int;
+		public var description : String;
+		public var startDate : Date;
+		public var endDate : Date;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/LayoutScrollEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/LayoutScrollEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/LayoutScrollEvent.as	(revision 15)
@@ -0,0 +1,46 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{
+	import mx.events.ScrollEvent;
+	
+	public class LayoutScrollEvent extends ScrollEvent
+	{
+		public static const ITEM_SCROLL : String = "itemScroll";
+		public static const PIXEL_SCROLL : String = "pixelScroll";
+		
+		public function LayoutScrollEvent( type : String )
+		{
+			super( type );
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/DatePositionConverter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/DatePositionConverter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/DatePositionConverter.as	(revision 15)
@@ -0,0 +1,84 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.utils
+{
+	/**
+	 * @private
+	 * Provide methods to convert pixel positions 
+	 * to dates and vice versa 
+	 */	
+	public class DatePositionConverter
+	{
+		public var startDateMilliseconds : Number;
+		public var totalWidth : Number;
+		public var totalMilliseconds : Number;
+		
+		public function positionToMilliseconds( position : Number ) : Number
+		{
+			return position / totalWidth * totalMilliseconds;
+		}
+		
+		public function millisecondsToPosition( milliseconds : Number ) : Number
+		{
+			return milliseconds / totalMilliseconds * totalWidth;	
+		}
+
+		public function positionToMillisecondsAbsolute( position : Number ) : Number
+		{
+			return startDateMilliseconds + positionToMilliseconds( position );
+		}
+		
+		public function millisecondsToPositionAbsolute( milliseconds : Number ) : Number
+		{
+			return millisecondsToPosition( milliseconds - startDateMilliseconds );	
+		}
+
+		public function positionToDate( position : Number ) : Date
+		{
+			return new Date( positionToMillisecondsAbsolute( position ));
+		}
+		
+		public function dateToPosition( date : Date ) : Number
+		{
+			return millisecondsToPositionAbsolute( date.getTime() );
+		}
+
+
+		public function toString() : String 
+		{
+			return "[object DatePositionConverter"
+				+ " startDateMilliseconds:" + startDateMilliseconds
+				+ " totalWidth:" + totalWidth
+				+ " totalMilliseconds:" + totalMilliseconds
+			    + "]";
+		}	
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/GraphicUtils.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/GraphicUtils.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/GraphicUtils.as	(revision 15)
@@ -0,0 +1,81 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.utils
+{
+	/**
+	 * @private
+	 */
+	public class GraphicUtils
+	{
+		
+		import flash.display.Graphics;
+		
+		public static function drawDottedHorizontalLineTo( 
+			g:Graphics, 
+			y : Number, 
+			xStart : Number, 
+			xEnd : Number 
+			) : void
+		{
+			for( var x : Number = xStart; x < xEnd; x += 3)
+			{
+				if( x % 2 == 0 )
+				{
+					g.lineTo( x + 3, y );
+				} 
+				else 
+				{
+					g.moveTo( x + 3, y );
+				}								
+			}
+		}		
+		
+		public static function drawDottedVerticalLineTo( 
+			g:Graphics, 
+			x : Number, 
+			yStart : Number, 
+			yEnd : Number 
+			) : void
+		{
+			for( var y : Number = yStart; y < yEnd; y += 3)
+			{
+				if( y % 2 == 0 )
+				{
+					g.lineTo( x, y + 3 );
+				} 
+				else 
+				{
+					g.moveTo( x, y + 3 );
+				}								
+			}
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/Selection.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/Selection.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/utils/Selection.as	(revision 15)
@@ -0,0 +1,128 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.utils
+{
+	import flash.utils.Dictionary;
+	
+	/**
+	 * @private
+	 */	
+	public class Selection
+	{
+		public var allowMultipleSelection : Boolean = false;
+		
+		protected var item : Object;
+		protected var items : Dictionary;
+		
+		public function Selection()
+		{
+			items = new Dictionary();
+		}
+		
+		public function hasItem( item : Object ) : Boolean
+		{
+			return items[ item ];	
+		}
+		
+		public function get selectedItem() : Object
+		{
+			return item;
+		}
+		
+		public function set selectedItem( value : Object ) : void
+		{
+			clear();
+			setItem( value );
+		}
+		
+		public function get selectedItems() : Array
+		{
+			var result : Array = new Array();
+			for each( var item : Object in items )
+			{
+				result.push( item );
+			}
+			return result;
+		}
+		
+		public function set selectedItems( newItems : Array ) : void
+		{
+			clear();
+			if( newItems == null ) return;
+			
+			for each( var item : Object in newItems )
+			{
+				items[ item ] = item;
+			}
+		}
+		
+		public function addItem( item : Object ) : void
+		{
+			if( allowMultipleSelection )
+			{
+				items[ item ] = item;			
+			}
+			else 
+			{
+				clear();
+				setItem( item );
+			}
+		}
+		
+		public function removeItem( item : Object ) : void
+		{
+			delete items[ item ];
+			this.item = null;
+		}
+		
+		public function clear() : void
+		{
+			item = null;
+			items = new Dictionary();		
+		}
+		
+		public function getNumberOfSelectedItems() : Number
+		{
+			var size : Number = 0;
+			for each( var item : Object in items )
+			{
+				size++;
+			}
+			return size;
+		}		
+		
+		private function setItem( value : Object ) : void
+		{
+			item = value;
+			items[ value ] = value;			
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/IHorizontalLinesViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/IHorizontalLinesViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/IHorizontalLinesViewer.as	(revision 15)
@@ -0,0 +1,51 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent;
+	
+	import mx.core.IUIComponent;
+	
+	public interface IHorizontalLinesViewer extends IUIComponent
+	{
+		function get dottedGridLines() : Boolean;
+		function set dottedGridLines( value : Boolean ) : void;
+		function get horizontalGridLineThickness() : Number;
+		function set horizontalGridLineThickness( value : Number ) : void;
+		function get horizontalGridLineColor() : uint;
+		function set horizontalGridLineColor( value : uint ) : void;
+		function get horizontalGridLineAlpha() : Number;
+		function set horizontalGridLineAlpha( value : Number ) : void;
+		
+		function update( event : LayoutUpdateEvent ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/IVerticalLinesViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/IVerticalLinesViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/IVerticalLinesViewer.as	(revision 15)
@@ -0,0 +1,51 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent;
+	
+	import mx.core.IUIComponent;
+	
+	public interface IVerticalLinesViewer extends IUIComponent
+	{
+		function get dottedGridLines() : Boolean;
+		function set dottedGridLines( value : Boolean ) : void;
+		function get verticalGridLineThickness() : Number;
+		function set verticalGridLineThickness( value : Number ) : void;
+		function get verticalGridLineColor() : uint;
+		function set verticalGridLineColor( value : uint ) : void;
+		function get verticalGridLineAlpha() : Number;
+		function set verticalGridLineAlpha( value : Number ) : void;
+		
+		function update( event : LayoutUpdateEvent ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/BackgroundViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/BackgroundViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/BackgroundViewer.as	(revision 15)
@@ -0,0 +1,134 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.BackgroundLayout;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.BackgroundLayoutItem;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers.BackgroundLayoutItemRenderer;
+	
+	import flash.display.DisplayObject;
+	import flash.events.Event;
+	
+	import mx.collections.ArrayCollection;
+	import mx.core.UIComponent;
+	import mx.events.ScrollEvent;	
+	
+	/**
+	 * @private
+	 */
+	public class BackgroundViewer extends UIComponent  
+	{		
+		private var freeRenderers : Array;
+		private var visibleRenderers : Array;
+		private var layout : BackgroundLayout;
+				
+		public function BackgroundViewer()
+		{
+			freeRenderers = new Array();
+			visibleRenderers = new Array();		
+		}
+		
+		public function update( event : Event ) : void
+		{
+			layout = event.target as BackgroundLayout;
+			invalidateDisplayList();
+		}
+		
+		protected override function measure() : void
+		{
+			super.measure();
+			if( layout )
+			{ 
+				measuredWidth = layout.contentWidth;
+				measuredHeight = 100;	
+			} 
+		}
+		
+		protected override function updateDisplayList( unscaledWidth : Number, unscaledHeight : Number ) : void
+		{
+			super.updateDisplayList( unscaledWidth , unscaledHeight );
+			render( layout );	
+		}
+		
+		private function render( layout : BackgroundLayout ) : void 
+		{
+			if( layout == null ) return;
+			
+			var oldRenderers : Array = visibleRenderers;
+			visibleRenderers = new Array();
+			
+			for each( var item : BackgroundLayoutItem in layout.items )
+			{
+				var renderer : BackgroundLayoutItemRenderer = oldRenderers.pop();
+				if( renderer != null )
+				{
+					renderer.x = item.x - layout.xPosition;
+					renderer.width = item.width;
+					renderer.height = item.height;
+					renderer.setStyle( "backgroundColor", item.backgroundColor );
+					renderer.toolTip = item.toolTip;
+				} 
+				else 
+				{
+					renderer = getRenderer();
+					
+					renderer.x = item.x - layout.xPosition;
+					renderer.width = item.width;
+					renderer.height = item.height;
+					renderer.setStyle( "backgroundColor", item.backgroundColor );
+					renderer.toolTip = item.toolTip;
+					
+					addChild( renderer );
+				}
+				visibleRenderers.push( renderer );
+			}
+			
+			removeUnusedRenderers( oldRenderers );			
+		}
+		
+		
+		private function removeUnusedRenderers( oldRenderers : Array ) : void
+		{
+			for each( var freeRenderer : DisplayObject in oldRenderers ){
+				freeRenderers.push( removeChild( freeRenderer ));
+			}
+		}
+		
+		private function getRenderer() : BackgroundLayoutItemRenderer
+		{
+			if( freeRenderers.length > 0 )
+			{
+				return freeRenderers.pop();
+			}
+			return new BackgroundLayoutItemRenderer();
+		}		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/EntryViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/EntryViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/EntryViewer.as	(revision 15)
@@ -0,0 +1,316 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers
+{
+	import flash.display.DisplayObject;
+	import flash.events.Event;
+	import flash.events.KeyboardEvent;
+	import flash.events.MouseEvent;
+	import flash.utils.Dictionary;
+	
+	import gssim.gssimstudio.editor.charts.scheduling.ScheduleViewer;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.EntryLayoutItem;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IEntryLayout;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers.GradientScheduleEntryRenderer;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers.IScheduleEntryRenderer;
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.utils.Selection;
+	
+	import mx.core.ClassFactory;
+	import mx.core.IFactory;
+	import mx.core.UIComponent;
+	
+	/**
+	 *  Name of CSS style declaration that specifies styles for the schedule entries
+	 */
+	[Style(name="entryStyleName", type="String", inherit="yes")]			
+
+	/**
+	 * @private
+	 */
+	public class EntryViewer extends UIComponent 
+	{
+		public var entryRenderer : IFactory;
+		private var freeRenderers : Array;
+		private var visibleRenderers : Dictionary;
+		private var layout : IEntryLayout;		
+		private var selection : Selection;
+		private var isShiftKey : Boolean;
+		private var isCtrlKey : Boolean;
+		
+		//private var owner : ScheduleViewer;
+		
+		public function EntryViewer(owner : ScheduleViewer)
+		{
+			this.owner = owner;
+			
+			entryRenderer = new ClassFactory( GradientScheduleEntryRenderer );
+			
+			freeRenderers = new Array();
+			visibleRenderers = new Dictionary();	
+			
+			selection = new Selection();
+			
+			addEventListener( MouseEvent.MOUSE_UP, onClickEntry );
+			addEventListener( Event.ACTIVATE, addKeyListeners );
+			addEventListener( Event.DEACTIVATE, removeKeyListeners );
+		}
+		
+		public function get allowMultipleSelection() : Boolean
+		{
+			return selection.allowMultipleSelection;
+		}
+		
+		public function set allowMultipleSelection( value : Boolean ) : void
+		{
+			selection.allowMultipleSelection = value;
+		}		
+		
+		public function get selectedItem() : IScheduleEntry
+		{
+			return IScheduleEntry( selection.selectedItem );
+		}
+		
+		public function set selectedItem( value : IScheduleEntry ) : void
+		{
+			selection.selectedItem = value;
+			invalidateDisplayList();
+		}
+		
+		public function get selectedItems() : Array
+		{
+			return selection.selectedItems
+		}
+		
+		public function set selectedItems( value : Array ) : void
+		{
+			selection.selectedItems = value;			
+		}
+		
+		public function update( event : LayoutUpdateEvent ) : void
+		{
+			layout = IEntryLayout( event.layout );
+			invalidateDisplayList();
+		}
+		
+		override protected function measure() : void
+		{
+			super.measure();
+			if( layout == null ) return;
+			
+			measuredWidth = layout.contentWidth;
+			measuredHeight = layout.contentHeight;
+		}
+		
+		override protected function updateDisplayList( unscaledWidth : Number, unscaledHeight : Number ) : void
+		{
+			super.updateDisplayList( unscaledWidth , unscaledHeight );			
+			render( layout );
+		}
+		
+		override protected function keyDownHandler( event : KeyboardEvent ) : void
+		{
+			super.keyDownHandler( event );
+			if( event.ctrlKey )
+			{
+				isCtrlKey = true;
+			}
+		}
+		
+		override protected function keyUpHandler( event : KeyboardEvent ) : void 
+		{
+			super.keyUpHandler( event );
+			if( !event.ctrlKey )
+			{
+				isCtrlKey = false;
+			}
+		}
+		
+		private function addKeyListeners( event : Event ) : void
+		{
+			if( stage == null ) return;
+			stage.addEventListener( KeyboardEvent.KEY_DOWN, keyDownHandler );
+			stage.addEventListener( KeyboardEvent.KEY_UP, keyUpHandler );	
+		}
+		
+		private function removeKeyListeners( event : Event ) : void
+		{
+			if( stage == null ) return;
+			stage.removeEventListener( KeyboardEvent.KEY_DOWN, keyDownHandler );
+			stage.removeEventListener( KeyboardEvent.KEY_UP, keyUpHandler );	
+		}		
+		
+		private function onClickEntry( event : MouseEvent ) : void 
+		{
+			event.stopPropagation();
+			
+			var renderer : IScheduleEntryRenderer = findRendererInParentChain( event.target );
+			if( renderer == null ) return;
+			
+			var entry : IScheduleEntry = renderer.entry;
+			createSelections( entry );
+			
+			owner.dispatchEvent(event);
+		}
+		
+		private function createSelections( entry : IScheduleEntry ) : void
+		{
+			if( entry == null ) return;
+			
+			if( !allowMultipleSelection )
+			{
+				selectOrDeselect( entry );
+			}
+			else
+			{
+				var hasZeroItems : Boolean = ( selection.selectedItems.length == 0 );					
+				if( hasZeroItems )
+				{
+					selection.addItem( entry );						
+				}
+				else
+				{
+					if( !isCtrlKey )
+					{
+						selection.clear();
+						selectOrDeselect( entry );
+					}
+					else
+					{						
+						selectOrDeselect( entry );
+					}	
+				}
+			}
+			
+			updateSelection();
+			dispatchEvent( new Event( "change" ) );
+		}
+		
+		private function selectOrDeselect( entry : IScheduleEntry ) : void
+		{
+			if( selection.hasItem( entry ) )
+			{
+				selection.removeItem( entry );
+			}
+			else 
+			{
+				selection.addItem( entry );
+			}		
+		}
+		
+		/**
+		 * Because we are relying on bubbling we 
+		 * have to make sure, that the event comes from the renderer 
+		 * actually and not from one of its child components. 
+		 * We traverse up the parent chain of the clicked target 
+		 * until we found an entryRenderer or null.
+		 * 
+		 * THINK : Normally i'd say, this is not our business, but 
+		 * we want to keep the renderer as simple as possible to make 
+		 * it easier for users to implement a renderer. Otherwise 
+		 * the renderer would have to catch events from its child 
+		 * components and redispatch them 
+		 */
+		private function findRendererInParentChain( target : Object ) : IScheduleEntryRenderer
+		{
+			while( target != null )
+			{
+				if( target is IScheduleEntryRenderer ) return target as IScheduleEntryRenderer;
+				target = target.parent;
+			}
+			return null;
+		}
+		
+		private function updateSelection() : void
+		{
+			for each( var renderer : IScheduleEntryRenderer in visibleRenderers )
+			{
+				renderer.selected = selection.hasItem( renderer.data );
+			}
+		}
+		
+		private function render( layout : IEntryLayout ) : void 
+		{
+			if( layout == null ) return;
+			
+			var oldRenderers : Dictionary = visibleRenderers;
+			visibleRenderers = new Dictionary();
+			
+			for each( var item : EntryLayoutItem in layout.items )
+			{
+				var renderer : IScheduleEntryRenderer = oldRenderers[ item ];
+				if( renderer != null )
+				{
+					renderer.x = item.x / item.zoom - layout.xPosition;
+					renderer.y = item.y - layout.yPosition + 2;
+					renderer.width = item.width / item.zoom;
+					renderer.height = item.height - 4;
+					delete oldRenderers[ item ];
+				}
+				else 
+				{
+					renderer = getRenderer();
+					var style : Object = getStyle( "entryStyleName" );
+					if( style != null ) renderer.styleName = style;
+					renderer.x = item.x / item.zoom - layout.xPosition;
+					renderer.y = item.y - layout.yPosition + 2;
+					renderer.width = item.width / item.zoom;
+					renderer.height = item.height - 4;
+					
+					addChild( DisplayObject( renderer ) );
+					renderer.data = item.data;
+				}
+				visibleRenderers[ item ] = renderer;
+			}
+			
+			removeUnusedRenderers( oldRenderers );			
+			updateSelection();
+		}
+		
+		private function removeUnusedRenderers( oldRenderers : Dictionary ) : void
+		{
+			for each( var freeRenderer : DisplayObject in oldRenderers )
+			{
+				freeRenderers.push( removeChild( freeRenderer ));
+			}
+		}
+		
+		private function getRenderer() : IScheduleEntryRenderer
+		{
+			if( freeRenderers.length > 0 )
+			{
+				return freeRenderers.pop();
+			}			
+			return entryRenderer.newInstance();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/HorizontalLinesViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/HorizontalLinesViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/HorizontalLinesViewer.as	(revision 15)
@@ -0,0 +1,156 @@
+/*
+
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+   @ignore
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers
+{
+  import flash.display.DisplayObject;
+  import flash.events.Event;
+  import flash.geom.Point;
+  import flash.geom.Rectangle;
+
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.HorizontalLinesLayout;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.HorizontalLinesLayoutItem;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IHorizontalLinesLayout;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.DottedHorizontalLineRenderer;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.ILineRenderer;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.LineRenderer;
+
+  import mx.core.UIComponent;
+
+  /**
+   * @private
+   */
+  public class HorizontalLinesViewer extends UIComponent implements IHorizontalLinesViewer
+  {
+    protected var layout:IHorizontalLinesLayout;
+
+    private var _dottedGridLines:Boolean;
+    private var _horizontalGridLineThickness:Number;
+    private var _horizontalGridLineColor:uint;
+    private var _horizontalGridLineAlpha:Number;
+
+    public function get dottedGridLines():Boolean
+    {
+      return _dottedGridLines;
+    }
+
+    public function set dottedGridLines(value:Boolean):void
+    {
+      _dottedGridLines = value;
+    }
+
+    public function get horizontalGridLineThickness():Number
+    {
+      return _horizontalGridLineThickness;
+    }
+
+    public function set horizontalGridLineThickness(value:Number):void
+    {
+      _horizontalGridLineThickness = value;
+    }
+
+    public function get horizontalGridLineColor():uint
+    {
+      return _horizontalGridLineColor;
+    }
+
+    public function set horizontalGridLineColor(value:uint):void
+    {
+      _horizontalGridLineColor = value;
+    }
+
+    public function get horizontalGridLineAlpha():Number
+    {
+      return _horizontalGridLineAlpha;
+    }
+
+    public function set horizontalGridLineAlpha(value:Number):void
+    {
+      _horizontalGridLineAlpha = value;
+    }
+
+    //---------------------------------------------		
+
+    public function update(event:LayoutUpdateEvent):void
+    {
+      layout = IHorizontalLinesLayout(event.layout);
+      invalidateDisplayList();
+    }
+
+    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+      super.updateDisplayList(unscaledWidth, unscaledHeight);
+      if (layout == null)
+        return;
+      graphics.clear();
+      render(layout);
+    }
+
+    protected function render(layout:IHorizontalLinesLayout):void
+    {
+      var lineRenderer:ILineRenderer = getLineRendererForStyling();
+
+      for each (var item:HorizontalLinesLayoutItem in layout.items)
+      {
+        drawLineForItem(item, lineRenderer);
+      }
+    }
+
+    protected function getLineRendererForStyling():ILineRenderer
+    {
+      var lineRenderer:ILineRenderer;
+      if (dottedGridLines)
+      {
+        lineRenderer = new DottedHorizontalLineRenderer();
+      }
+      else
+      {
+        lineRenderer = new LineRenderer();
+      }
+      lineRenderer.weight = horizontalGridLineThickness;
+      lineRenderer.color = horizontalGridLineColor;
+      lineRenderer.alpha = horizontalGridLineAlpha;
+      return lineRenderer;
+    }
+
+    protected function drawLineForItem(item:HorizontalLinesLayoutItem, lineRenderer:ILineRenderer):void
+    {
+      var y:Number = item.y - layout.yPosition;
+      lineRenderer.moveTo(graphics, 0, y);
+
+
+        lineRenderer.apply(graphics, null, null);
+
+      lineRenderer.drawTo(graphics, item.width, y);
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/VerticalLinesViewer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/VerticalLinesViewer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/viewers/VerticalLinesViewer.as	(revision 15)
@@ -0,0 +1,152 @@
+/*
+
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+   @ignore
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.viewers
+{
+  import flash.geom.Point;
+  import flash.geom.Rectangle;
+
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IVerticalLinesLayout;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.LayoutUpdateEvent;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.VerticalLinesLayoutItem;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.DottedVerticalLineRenderer;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.ILineRenderer;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.lineRenderer.LineRenderer;
+
+  import mx.core.UIComponent;
+
+  /**
+   * @private
+   */
+  public class VerticalLinesViewer extends UIComponent implements IVerticalLinesViewer
+  {
+    private var layout:IVerticalLinesLayout;
+
+    private var _dottedGridLines:Boolean;
+    private var _verticalGridLineThickness:Number;
+    private var _verticalGridLineColor:uint;
+    private var _verticalGridLineAlpha:Number;
+
+    public function get dottedGridLines():Boolean
+    {
+      return _dottedGridLines;
+    }
+
+    public function set dottedGridLines(value:Boolean):void
+    {
+      _dottedGridLines = value;
+    }
+
+    public function get verticalGridLineThickness():Number
+    {
+      return _verticalGridLineThickness;
+    }
+
+    public function set verticalGridLineThickness(value:Number):void
+    {
+      _verticalGridLineThickness = value;
+    }
+
+    public function get verticalGridLineColor():uint
+    {
+      return _verticalGridLineColor;
+    }
+
+    public function set verticalGridLineColor(value:uint):void
+    {
+      _verticalGridLineColor = value;
+    }
+
+    public function get verticalGridLineAlpha():Number
+    {
+      return _verticalGridLineAlpha;
+    }
+
+    public function set verticalGridLineAlpha(value:Number):void
+    {
+      _verticalGridLineAlpha = value;
+    }
+
+    //---------------------------------------------		
+
+    public function update(event:LayoutUpdateEvent):void
+    {
+      layout = IVerticalLinesLayout(event.layout);
+      invalidateDisplayList();
+    }
+
+    protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+      super.updateDisplayList(unscaledWidth, unscaledHeight);
+      if (layout == null)
+        return;
+      graphics.clear();
+      render(layout);
+    }
+
+    protected function render(layout:IVerticalLinesLayout):void
+    {
+      var lineRenderer:ILineRenderer = getLineRendererForStyling();
+
+      for each (var item:VerticalLinesLayoutItem in layout.items)
+      {
+        drawLineForItem(item, lineRenderer);
+      }
+    }
+
+    protected function getLineRendererForStyling():ILineRenderer
+    {
+      var lineRenderer:ILineRenderer;
+      if (dottedGridLines)
+      {
+        lineRenderer = new DottedVerticalLineRenderer();
+      }
+      else
+      {
+        lineRenderer = new LineRenderer();
+      }
+      lineRenderer.weight = verticalGridLineThickness;
+      lineRenderer.color = verticalGridLineColor;
+      lineRenderer.alpha = verticalGridLineAlpha;
+      return lineRenderer;
+    }
+
+    protected function drawLineForItem(item:VerticalLinesLayoutItem, lineRenderer:ILineRenderer):void
+    {
+      var x:Number = item.x - layout.xPosition;
+      lineRenderer.moveTo(graphics, x, 0);
+
+        lineRenderer.apply(graphics, null, null);
+
+      lineRenderer.drawTo(graphics, x, item.height);
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/ColoredScheduleEntry.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/ColoredScheduleEntry.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/ColoredScheduleEntry.as	(revision 15)
@@ -0,0 +1,46 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+
+	/**
+	 */
+	public class ColoredScheduleEntry extends SimpleScheduleEntry implements IScheduleEntry
+	{
+		public var backgroundColor : int = 0xcccccc;
+		
+		override public function toString() : String
+		{
+			return "[object ColoredScheduleEntry startDate:" + startDate + " endDate:" + endDate + "]";
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/IScheduleEntry.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/IScheduleEntry.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/IScheduleEntry.as	(revision 15)
@@ -0,0 +1,42 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{
+	/**
+	 */	
+	public interface IScheduleEntry
+	{
+		function get startDate() : Date;
+		function set startDate( value : Date ) : void;
+		function get endDate() : Date;
+		function set endDate ( value : Date ) : void;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/ScheduleNavigator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/ScheduleNavigator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/ScheduleNavigator.as	(revision 15)
@@ -0,0 +1,398 @@
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses
+{
+   import gssim.gssimstudio.editor.charts.scheduling.ScheduleViewer;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.EntryLayoutItem;
+   import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.IEntryLayout;
+   
+   import flash.events.Event;
+   import flash.events.EventDispatcher;
+   import flash.events.MouseEvent;
+   
+   import mx.controls.scrollClasses.ScrollBar;
+   import mx.core.ScrollPolicy;
+   import mx.effects.AnimateProperty;
+   import mx.events.EffectEvent;
+   import mx.events.ScrollEvent;
+   import mx.events.ScrollEventDirection;
+   
+   use namespace schedule_internal;
+   
+   [Event(name="invalidateDisplayList", type="flash.events.Event")]
+   public class ScheduleNavigator extends EventDispatcher
+   {
+      public static const INVALIDATE_DISPLAY_LIST : String = "invalidateDisplayList";
+      
+      public var entryLayoutImpl : IEntryLayout;
+		public var contentWidthOffset : Number;
+		public var contentHeightOffset : Number;      
+      private var owner : ScheduleViewer;
+      private var _pixelScrollEnabled : Boolean;
+      private var hasPixelScrollWhileAnimating : Boolean    
+ 		private var _xPosition : Number;
+		private var _yPosition : Number;
+		private var _xPositionWithOffset : Number;
+		private var _yPositionWithOffset : Number;		
+		private var _xOffset : Number;
+		private var _yOffset : Number;	
+		private var _zoom : Number;     
+      
+      public function ScheduleNavigator( owner : ScheduleViewer )
+      {
+         this.owner = owner;
+         
+			owner.horizontalScrollPolicy = ScrollPolicy.AUTO;
+			owner.verticalScrollPolicy = ScrollPolicy.AUTO;         
+         
+         pixelScrollEnabled = true;
+			_xPosition = 0;
+			_yPosition = 0;
+			_xPositionWithOffset = 0;
+			_yPositionWithOffset = 0;
+			_zoom = 100;
+			xOffset = 50;
+			yOffset = 50;
+			contentWidthOffset = 0;
+			contentHeightOffset = 0;         
+      }
+      
+ 		public function mouseWheelHandler( event : MouseEvent ) : void
+		{
+        var verticalScrollBar : ScrollBar = owner.verticalScrollBar;
+         
+      
+         var oldPosition : Number = owner.verticalScrollPosition;
+         var newPos : int = owner.verticalScrollPosition;
+         var lineScrollSize : Number;
+         if( !isItemScroll() )
+         {
+         	lineScrollSize = owner.rowHeight / 3;
+         }
+         else
+         {
+         	lineScrollSize = verticalScrollBar.lineScrollSize / 3;
+         }
+         newPos -= event.delta * lineScrollSize;	   
+         newPos = Math.max( 0, Math.min( newPos, verticalScrollBar.maxScrollPosition ) );
+         owner.verticalScrollPosition = newPos;
+          
+         if ( oldPosition != owner.verticalScrollPosition )
+         {
+             var scrollEvent:ScrollEvent = new ScrollEvent( ScrollEvent.SCROLL );
+             scrollEvent.direction = ScrollEventDirection.VERTICAL;
+         	 scrollEvent.position = getPixelOrItemScroll( owner.verticalScrollPosition );				     
+             scrollEvent.delta = owner.verticalScrollPosition - oldPosition;
+             owner.dispatchEvent( scrollEvent );
+         }
+        
+      }
+		
+		//dispatch item scroll event only when the row item changes.
+		public function onScroll( event : ScrollEvent ) : void
+		{
+			var position : Number = event.position;			
+			var newIndex : Number;
+			var oldIndex : Number;
+			var delta : Number;
+			
+			if( event.direction == ScrollEventDirection.HORIZONTAL )
+			{
+				setXPosition( position );
+			}
+			else
+			{
+				newIndex = Math.floor( position / owner.rowHeight );
+				oldIndex = Math.floor( entryLayoutImpl.yPosition / owner.rowHeight );
+				delta = oldIndex - newIndex;
+				
+				setYPosition( position );
+				
+				if( delta != 0 )
+				{
+					var itemScrollEvent : LayoutScrollEvent = new LayoutScrollEvent( LayoutScrollEvent.ITEM_SCROLL );
+					itemScrollEvent.direction = event.direction;
+					itemScrollEvent.position = newIndex;
+					itemScrollEvent.delta = delta;
+					itemScrollEvent.detail = event.detail;
+					owner.dispatchEvent( itemScrollEvent );			
+				}
+			}
+		}			
+		
+		public function scrollHandler( event : Event ) : void
+		{
+			var scrollEvent : ScrollEvent = ScrollEvent( event );
+			if( scrollEvent.direction == ScrollEventDirection.VERTICAL )
+			{
+				scrollEvent.position = getPixelOrItemScroll( scrollEvent.position );
+			}
+			onScroll( scrollEvent );
+		}		
+		
+		public function updateItemScroll() : void
+		{
+			if( isItemScroll() )
+			{
+				owner.yOffset = convertPixelToItemPosition( owner.yOffset );
+				owner.verticalScrollBar.lineScrollSize = owner.rowHeight;
+			}
+		}
+		
+		public function get pixelScrollEnabled() : Boolean
+		{
+			return _pixelScrollEnabled;
+		}
+		
+		public function set pixelScrollEnabled( value : Boolean ) : void
+		{
+			_pixelScrollEnabled = value;
+			dispatchEvent( new Event( ScheduleNavigator.INVALIDATE_DISPLAY_LIST ) );
+		}
+		
+		//navigation				
+		
+		[Bindable]
+		public function get zoom() : Number
+		{
+			return _zoom;
+		}
+		
+		public function set zoom( value : Number ) : void
+		{
+			_zoom = value;
+			var adjustedValue : Number = value / 100 * Math.sqrt( owner.width );
+			contentWidth = Math.pow( adjustedValue, 2 );
+		}
+		
+		[Bindable]
+		public function get contentWidth() : Number
+		{
+			return entryLayoutImpl.contentWidth;
+		}
+		
+		public function set contentWidth( value : Number ) : void
+		{
+			owner.horizontalScrollPosition *= value / entryLayoutImpl.contentWidth;
+			if( isNaN( owner.horizontalScrollPosition ) ) owner.horizontalScrollPosition = 0;
+			
+			entryLayoutImpl.contentWidth = value;
+			
+			dispatchEvent( new Event( ScheduleNavigator.INVALIDATE_DISPLAY_LIST ) );
+		}
+		
+		[Bindable]
+		public function get xPosition() : Number
+		{
+			return _xPosition;
+		}
+		
+		public function set xPosition( position : Number ) : void
+		{
+			_xPosition = position;
+			setHorizontalScrollPosition( position );
+			var overlap : Number = entryLayoutImpl.contentWidth - entryLayoutImpl.viewportWidth;
+			if( overlap < position )
+			{
+				contentWidthOffset = position - overlap;
+				dispatchEvent( new Event( ScheduleNavigator.INVALIDATE_DISPLAY_LIST ) );
+			}
+		}
+		
+		[Bindable]
+		public function get yPosition() : Number
+		{
+			return _yPosition;
+		}
+		
+		public function set yPosition( position : Number ) : void
+		{
+			_yPosition = position;
+			setVerticalScrollPosition( position );
+			var overlap : Number = entryLayoutImpl.contentHeight - entryLayoutImpl.viewportHeight;
+			if( overlap < position )
+			{
+				contentHeightOffset = position - overlap;				
+				dispatchEvent( new Event( ScheduleNavigator.INVALIDATE_DISPLAY_LIST ) );
+			}
+		}
+		
+		[Bindable]
+		public function get xPositionWithOffset() : Number
+		{
+			return _xPositionWithOffset;
+		}
+		
+		public function set xPositionWithOffset( position : Number ) : void
+		{
+			_xPositionWithOffset = position - xOffset;
+			setHorizontalScrollPosition( _xPositionWithOffset );
+		}
+		
+		[Bindable]
+		public function get yPositionWithOffset() : Number
+		{
+			return _yPositionWithOffset;
+		}
+							
+		public function set yPositionWithOffset( position : Number ) : void
+		{
+			_yPositionWithOffset = position - yOffset;
+			setVerticalScrollPosition( _yPositionWithOffset );
+		}
+		
+		[Bindable]
+		public function get xOffset() : Number
+		{
+			return _xOffset;
+		}
+		
+		public function set xOffset( value : Number ) : void
+		{
+			_xOffset = value;
+		}
+		
+		[Bindable]
+		public function get yOffset() : Number
+		{
+			return _yOffset;
+		}
+		
+		public function set yOffset( value : Number ) : void
+		{
+			_yOffset = value;
+		}			
+		
+		public function gotoTime( milliseconds : Number ) : void
+		{
+			var position : Number = milliseconds * entryLayoutImpl.contentWidth / entryLayoutImpl.totalMilliseconds;
+			owner.xPosition = position;
+		}
+
+		public function moveToTime( milliseconds : Number ) : void
+		{
+			var position : Number = milliseconds * entryLayoutImpl.contentWidth / entryLayoutImpl.totalMilliseconds;
+			animateHorizontalScrollPosition( position );
+		}
+		
+		public function gotoEntry( entry : IScheduleEntry ) : void
+		{
+			var milliseconds : Number = entry.startDate.getTime() - entryLayoutImpl.startDate.getTime();
+			gotoTime( milliseconds );
+			
+			var item : EntryLayoutItem = entryLayoutImpl.findLayoutItem( entry );
+			owner.yPosition = item.y;
+		}
+		
+		public function moveToEntry( entry : IScheduleEntry ) : void
+		{
+			var milliseconds : Number = entry.startDate.getTime() - entryLayoutImpl.startDate.getTime();
+			moveToTime( milliseconds );
+			
+			var item : EntryLayoutItem = entryLayoutImpl.findLayoutItem( entry );
+			animateVerticalScrollPosition( item.y );
+		}		
+		
+		private function animateHorizontalScrollPosition( position : Number ) : void
+		{
+			var e : AnimateProperty = new AnimateProperty( this );
+			e.property = "xPosition";
+			e.fromValue = owner.horizontalScrollPosition;
+			e.toValue = position - owner.xOffset;
+			e.duration = owner.getStyle( "moveDuration" );
+			e.easingFunction = owner.getStyle( "moveEasingFunction" ) as Function;
+			e.play();
+		}		
+		
+		
+		private function animateVerticalScrollPosition( position : Number ) : void
+		{
+			if( !pixelScrollEnabled ) 
+			{
+				pixelScrollEnabled = true;
+				hasPixelScrollWhileAnimating = true;
+			}
+			var e : AnimateProperty = new AnimateProperty( this );
+			e.property = "yPosition";
+			e.fromValue = owner.verticalScrollPosition;
+			e.toValue = position - owner.yOffset;
+			e.duration = owner.getStyle( "moveDuration" );
+			e.easingFunction = owner.getStyle( "moveEasingFunction" ) as Function;
+			e.addEventListener( EffectEvent.EFFECT_END, verticalAnimationEnd );
+			e.play();
+		}
+		
+		private function verticalAnimationEnd( event : EffectEvent ) : void
+		{
+			if( hasPixelScrollWhileAnimating )
+			{				
+				pixelScrollEnabled = false;
+				hasPixelScrollWhileAnimating = false;
+			}
+		}
+				
+		private function setHorizontalScrollPosition( value : Number ) : void
+		{
+			var event : ScrollEvent = new ScrollEvent( ScrollEvent.SCROLL );
+			event.direction = ScrollEventDirection.HORIZONTAL;
+			event.position = value;
+			event.delta = owner.horizontalScrollPosition - value;
+			event.detail = "custom";
+			owner.horizontalScrollPosition = value;			
+			owner.dispatchEvent( event );
+			
+			var itemScrollEvent : LayoutScrollEvent = new LayoutScrollEvent( LayoutScrollEvent.PIXEL_SCROLL );
+			itemScrollEvent.direction = ScrollEventDirection.HORIZONTAL;
+			itemScrollEvent.position = value;
+			itemScrollEvent.delta = owner.horizontalScrollPosition - value;
+			itemScrollEvent.detail = "custom";
+			owner.dispatchEvent( itemScrollEvent );
+		}
+		
+		private function setVerticalScrollPosition( value : Number ) : void
+		{
+			var event : ScrollEvent = new ScrollEvent( ScrollEvent.SCROLL );
+			event.direction = ScrollEventDirection.VERTICAL;
+			event.position = value;
+			event.delta = owner.verticalScrollPosition - value;
+			event.detail = "custom";
+			owner.verticalScrollPosition = value;			
+			owner.dispatchEvent( event );
+			
+			var itemScrollEvent : LayoutScrollEvent = new LayoutScrollEvent( LayoutScrollEvent.PIXEL_SCROLL );
+			itemScrollEvent.direction = ScrollEventDirection.VERTICAL;
+			itemScrollEvent.position = value;
+			itemScrollEvent.delta = owner.verticalScrollPosition - value;
+			itemScrollEvent.detail = "custom";
+			owner.dispatchEvent( itemScrollEvent );
+		}		
+		
+		private function isItemScroll() : Boolean
+		{
+			return ( owner.verticalScrollBar != null && !pixelScrollEnabled );
+		}
+		
+		private function getPixelOrItemScroll( pixelPosition : Number ) : Number
+		{
+			var position : Number = pixelPosition;
+			if( !pixelScrollEnabled ) position = convertPixelToItemPosition( position ); 
+			return position;			
+		}
+		
+		private function convertPixelToItemPosition( pixelPosition : Number ) : Number
+		{
+			var rowCount : Number = pixelPosition / owner.rowHeight;
+			return Math.floor( rowCount ) * owner.rowHeight;			
+		}
+		
+		private function setXPosition( position : Number ) : void
+		{
+			entryLayoutImpl.xPosition = position;
+			entryLayoutImpl.update();
+		}
+		
+		private function setYPosition( position : Number ) : void
+		{
+			entryLayoutImpl.yPosition = position;
+			entryLayoutImpl.update();
+		}				 
+   }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/ColoredGradientScheduleEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/ColoredGradientScheduleEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/ColoredGradientScheduleEntryRenderer.as	(revision 15)
@@ -0,0 +1,58 @@
+/*
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers
+{
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.ColoredScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.SimpleScheduleEntry;
+
+  import mx.utils.ColorUtil;
+
+  public class ColoredGradientScheduleEntryRenderer extends AbstractGradientScheduleEntryRenderer
+  {
+    public function ColoredGradientScheduleEntryRenderer()
+    {
+      super();
+    }
+
+    override public function set data(value:Object):void
+    {
+      super.data = value;
+
+      entry = value as IScheduleEntry;
+      var content:ColoredScheduleEntry = ColoredScheduleEntry(entry);
+
+      var newColor:uint = ColorUtil.adjustBrightness2(content.backgroundColor, 25);
+      setStyle("fillColors", [newColor, content.backgroundColor]);
+
+      setTextContent(SimpleScheduleEntry(content));
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/IScheduleEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/IScheduleEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/IScheduleEntryRenderer.as	(revision 15)
@@ -0,0 +1,50 @@
+/*
+
+Copyright (c) 2006. Adobe Systems Incorporated.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of Adobe Systems Incorporated nor the names of its
+    contributors may be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+@ignore
+*/
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers
+{
+	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+	
+	import mx.core.IDataRenderer;
+	import mx.core.IFlexDisplayObject;
+	import mx.styles.IStyleClient;
+	
+	/**
+	 */	
+	public interface IScheduleEntryRenderer extends IFlexDisplayObject, IDataRenderer, IStyleClient
+	{
+		function get entry() : IScheduleEntry;
+		function set entry( value : IScheduleEntry ) : void;
+		
+		function get selected() : Boolean;
+		function set selected( value : Boolean ) : void;		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/SolidScheduleEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/SolidScheduleEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/SolidScheduleEntryRenderer.as	(revision 15)
@@ -0,0 +1,53 @@
+/*
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers
+{
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.SimpleScheduleEntry;
+
+
+  public class SolidScheduleEntryRenderer extends AbstractSolidScheduleEntryRenderer
+  {
+    public function SolidScheduleEntryRenderer()
+    {
+            super();
+    }
+
+    override public function set data(value:Object):void
+    {
+      super.data = value;
+
+      entry = value as IScheduleEntry;
+      var content:SimpleScheduleEntry = SimpleScheduleEntry(entry);
+
+      setTextContent(content);
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/BackgroundLayoutItemRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/BackgroundLayoutItemRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/BackgroundLayoutItemRenderer.as	(revision 15)
@@ -0,0 +1,41 @@
+/*
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers
+{
+  import mx.containers.Box;
+
+  public class BackgroundLayoutItemRenderer extends Box
+  {
+    public function BackgroundLayoutItemRenderer()
+    {
+      super();
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/GradientScheduleEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/GradientScheduleEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/GradientScheduleEntryRenderer.as	(revision 15)
@@ -0,0 +1,52 @@
+/*
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers
+{
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.SimpleScheduleEntry;
+
+  public class GradientScheduleEntryRenderer extends AbstractGradientScheduleEntryRenderer
+  {
+    public function GradientScheduleEntryRenderer()
+    {
+      super();
+    }
+
+    override public function set data(value:Object):void
+    {
+      super.data = value;
+
+      entry = value as IScheduleEntry;
+      var content:SimpleScheduleEntry = SimpleScheduleEntry(entry);
+
+      setTextContent(content);
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/AbstractSolidScheduleEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/AbstractSolidScheduleEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/AbstractSolidScheduleEntryRenderer.as	(revision 15)
@@ -0,0 +1,211 @@
+/*
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers
+{
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.SimpleScheduleEntry;
+
+  import mx.containers.Box;
+  import mx.controls.Alert;
+  import mx.controls.Label;
+  import mx.controls.Text;
+  import mx.core.ScrollPolicy;
+  import mx.formatters.DateFormatter;
+  import mx.styles.CSSStyleDeclaration;
+  import mx.styles.StyleManager;
+
+  import mx.core.mx_internal;
+
+  public class AbstractSolidScheduleEntryRenderer extends Box implements IScheduleEntryRenderer
+  {
+    public var contentLabel:Label;
+    public var contentText:Text;
+
+    private var defaultLabel:String = "";
+    private var formatter:DateFormatter;
+    private var formatString:String = "L:NNAA";
+    private var _entry:IScheduleEntry;
+    private var _selected:Boolean = false;
+
+    public function get entry():IScheduleEntry
+    {
+      return _entry;
+    }
+
+    public function set entry(value:IScheduleEntry):void
+    {
+      _entry = value;
+    }
+
+    public function get selected():Boolean
+    {
+      return _selected;
+    }
+
+    public function set selected(value:Boolean):void
+    {
+      _selected = value;
+      updateSelected();
+    }
+
+    public function AbstractSolidScheduleEntryRenderer()
+    {
+      super();
+
+      formatter = new DateFormatter();
+      formatter.formatString = formatString;
+
+      //	our style settings
+      //	initialize component styles
+      if (!this.styleDeclaration)
+      {
+        this.styleDeclaration = new CSSStyleDeclaration();
+      }
+      this.styleDeclaration.defaultFactory = function():void
+      {
+        this.borderStyle = "solid";
+      };
+
+      mx_internal::initStyles();
+
+      //	properties
+      this.verticalScrollPolicy = "off";
+      this.horizontalScrollPolicy = "off";
+      this.styleName = "defaultEntryStyle";
+    }
+
+    mx_internal static var stylesInitialized:Boolean = false;
+
+    mx_internal function initStyles():void
+    {
+      //	only add our style defs to the StyleManager once
+      if (mx_internal::stylesInitialized)
+      {
+        return;
+      }
+      else
+      {
+        mx_internal::stylesInitialized = true;
+      }
+
+      var style:CSSStyleDeclaration;
+      var effects:Array;
+
+      // defaultTimeStyle
+      style = styleManager.getStyleDeclaration(".defaultTimeStyle");
+      if (!style)
+      {
+        style = new CSSStyleDeclaration();
+        styleManager.setStyleDeclaration(".defaultTimeStyle", style, false);
+      }
+      if (style.factory == null)
+      {
+        style.factory = function():void
+        {
+          this.fontWeight = "bold";
+          this.color = 0x000000;
+          this.fontSize = 9;
+        };
+      }
+      // defaultEntryStyle
+      style = styleManager.getStyleDeclaration(".defaultEntryStyle");
+      if (!style)
+      {
+        style = new CSSStyleDeclaration();
+        styleManager.setStyleDeclaration(".defaultEntryStyle", style, false);
+      }
+      if (style.factory == null)
+      {
+        style.factory = function():void
+        {
+          this.fontWeight = "normal";
+          this.timeStyleName = "defaultTimeStyle";
+          this.paddingTop = 5;
+          this.color = 0x000000;
+          this.backgroundColor = 0xcccccc;
+          this.fontSize = 11;
+          this.verticalGap = -2;
+          this.paddingBottom = 5;
+          this.paddingLeft = 5;
+          this.paddingRight = 5;
+        };
+      }
+
+    }
+
+    override protected function createChildren():void
+    {
+      super.createChildren();
+      contentLabel = new Label();
+      addChild(contentLabel);
+
+      contentText = new Text();
+      addChild(contentText);
+    }
+
+    private function updateSelected():void
+    {
+      if (_selected)
+      {
+        setStyle("dropShadowEnabled", true);
+        setStyle("borderColor", 0xffffff);
+        setStyle("borderThickness", 2);
+        alpha = 1.00;
+      }
+      else
+      {
+        setStyle("dropShadowEnabled", false);
+        setStyle("borderColor", 0xcccccc);
+        setStyle("borderThickness", 1);
+        alpha = 0.60;
+      }
+    }
+
+
+    protected function setTextContent(content:SimpleScheduleEntry):void
+    {
+      if (content.label == null)
+        content.label = defaultLabel;
+
+      formatter.error = "";
+      var time:String = formatter.format(content.startDate)
+        + " - " + formatter.format(content.endDate);
+
+      toolTip = time + "\n" + content.label;
+      contentLabel.text = time;
+      contentLabel.styleName = getStyle("timeStyleName");
+      contentText.text = content.label;
+
+      updateSelected();
+    }
+
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/AbstractGradientScheduleEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/AbstractGradientScheduleEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/AbstractGradientScheduleEntryRenderer.as	(revision 15)
@@ -0,0 +1,266 @@
+/*
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers
+{
+  import flash.display.GradientType;
+  import flash.geom.Matrix;
+
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.SimpleScheduleEntry;
+
+  import mx.containers.Box;
+  import mx.controls.Label;
+  import mx.controls.Text;
+  import mx.core.ScrollPolicy;
+  import mx.core.mx_internal;
+  import mx.formatters.DateFormatter;
+  import mx.styles.CSSStyleDeclaration;
+  import mx.styles.StyleManager;
+  import mx.utils.ColorUtil;
+
+  public class AbstractGradientScheduleEntryRenderer extends Box implements IScheduleEntryRenderer
+  {
+
+    public var contentLabel:Label;
+    public var contentText:Text;
+
+    private var defaultLabel:String = "";
+    private var formatter:DateFormatter;
+    private var formatString:String = "L:NNAA";
+    private var origFillColors:Array;
+    private var changeSelection:Boolean;
+    private var _entry:IScheduleEntry;
+    private var _selected:Boolean = false;
+
+    private var gradientChanged:Boolean = true;
+
+
+    public function get entry():IScheduleEntry
+    {
+      return _entry;
+    }
+
+    public function set entry(value:IScheduleEntry):void
+    {
+      _entry = value;
+    }
+
+    public function get selected():Boolean
+    {
+      return _selected;
+    }
+
+    public function set selected(value:Boolean):void
+    {
+      _selected = value;
+      updateSelected();
+    }
+
+
+
+    public function AbstractGradientScheduleEntryRenderer()
+    {
+      super();
+      formatter = new DateFormatter();
+      formatter.formatString = formatString;
+
+
+      horizontalScrollPolicy = ScrollPolicy.OFF;
+      verticalScrollPolicy = ScrollPolicy.OFF;
+
+      //	our style settings
+      //	initialize component styles
+      if (!this.styleDeclaration)
+      {
+        this.styleDeclaration = new CSSStyleDeclaration();
+      }
+
+      this.styleDeclaration.defaultFactory = function():void
+      {
+        this.borderStyle = "applicationControlBar";
+      };
+
+      mx_internal::initStyles();
+      //	properties
+      this.styleName = "defaultEntryStyle";
+      this.verticalScrollPolicy = "off";
+      this.horizontalScrollPolicy = "off";
+
+    }
+
+    mx_internal var stylesInitialized:Boolean = false;
+
+    mx_internal function initStyles():void
+    {
+      //	only add our style defs to the StyleManager once
+      if (mx_internal::stylesInitialized)
+      {
+        return;
+      }
+      else
+      {
+        mx_internal::stylesInitialized = true;
+      }
+
+      var style:CSSStyleDeclaration;
+      var effects:Array;
+
+      // defaultTimeStyle
+      style = styleManager.getStyleDeclaration(".defaultTimeStyle");
+      if (!style)
+      {
+        style = new CSSStyleDeclaration();
+        styleManager.setStyleDeclaration(".defaultTimeStyle", style, false);
+      }
+      if (style.factory == null)
+      {
+        style.factory = function():void
+        {
+          this.fontWeight = "bold";
+          this.color = 0x000000;
+          this.fontSize = 9;
+        };
+      }
+      // defaultEntryStyle
+      style = styleManager.getStyleDeclaration(".defaultEntryStyle");
+      if (!style)
+      {
+        style = new CSSStyleDeclaration();
+        styleManager.setStyleDeclaration(".defaultEntryStyle", style, false);
+      }
+      if (style.factory == null)
+      {
+        style.factory = function():void
+        {
+          this.borderStyle = "default";
+          this.timeStyleName = "defaultTimeStyle";
+          this.paddingTop = 5;
+          this.shadowDistance = 2;
+          this.cornerRadius = 6;
+          this.fontSize = 11;
+          this.verticalGap = -2;
+          this.fillAlphas = [1, 1];
+          this.paddingLeft = 5;
+          this.paddingRight = 5;
+          this.fontWeight = "normal";
+          this.dropShadowEnabled = true;
+          this.color = 0xffffff;
+          this.borderThickness = 1;
+          this.highlightAlphas = [0.08, 0];
+          this.fillColors = [0x7aa4bc, 0x53839f];
+          this.paddingBottom = 5;
+        };
+      }
+    }
+
+    override protected function createChildren():void
+    {
+      super.createChildren();
+      contentLabel = new Label();
+      addChild(contentLabel);
+
+      contentText = new Text();
+      addChild(contentText);
+    }
+
+    /**
+     * @private
+     */
+    override public function styleChanged(styleProp:String):void
+    {
+      super.styleChanged(styleProp);
+      if (styleProp != null)
+      {
+
+        if (styleProp == "fillColors" && !changeSelection)
+        {
+          origFillColors = getStyle(styleProp);
+        }
+        else if (changeSelection)
+        {
+          changeSelection = false;
+        }
+
+        if (styleProp == "fillColors")
+        {
+          gradientChanged = true;
+          invalidateDisplayList();
+        }
+      }
+    }
+
+    private function updateSelected():void
+    {
+      var newColor1:uint;
+      var newColor2:uint;
+      if (origFillColors == null)
+      {
+        origFillColors = getStyle("fillColors");
+      }
+
+      if (_selected)
+      {
+        setStyle("dropShadowEnabled", true);
+        changeSelection = true;
+        newColor1 = ColorUtil.adjustBrightness2(origFillColors[0], 25);
+        newColor2 = ColorUtil.adjustBrightness2(origFillColors[1], 25);
+        setStyle("fillColors", [newColor1, newColor2]);
+      }
+      else
+      {
+        setStyle("dropShadowEnabled", false);
+        changeSelection = true;
+        newColor1 = ColorUtil.adjustBrightness2(origFillColors[0], 0);
+        newColor2 = ColorUtil.adjustBrightness2(origFillColors[1], 0);
+        setStyle("fillColors", [newColor1, newColor2]);
+      }
+    }
+
+    protected function setTextContent(content:SimpleScheduleEntry):void
+    {
+      if (content.label == null)
+      {
+        content.label = defaultLabel;
+      }
+
+      formatter.error = "";
+      var time:String = formatter.format(content.startDate)
+        + " - " + formatter.format(content.endDate);
+
+      toolTip = time + "\n" + content.label;
+      contentLabel.text = time;
+      contentLabel.styleName = getStyle("timeStyleName");
+      contentText.text = content.label;
+
+      updateSelected();
+    }
+
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/ColoredSolidScheduleEntryRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/ColoredSolidScheduleEntryRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/scheduling/scheduleClasses/renderers/ColoredSolidScheduleEntryRenderer.as	(revision 15)
@@ -0,0 +1,56 @@
+/*
+   Copyright (c) 2006. Adobe Systems Incorporated.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of Adobe Systems Incorporated nor the names of its
+   contributors may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers
+{
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.ColoredScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.IScheduleEntry;
+  import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.SimpleScheduleEntry;
+
+
+  public class ColoredSolidScheduleEntryRenderer extends AbstractSolidScheduleEntryRenderer
+  {
+    public function ColoredSolidScheduleEntryRenderer()
+    {
+      super();
+    }
+
+    override public function set data(value:Object):void
+    {
+      super.data = value;
+
+      entry = value as IScheduleEntry;
+      var content:ColoredScheduleEntry = ColoredScheduleEntry(entry);
+
+      setStyle("backgroundColor", content.backgroundColor);
+
+      setTextContent(SimpleScheduleEntry(content));
+    }
+  }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ExperimentComparisonChart.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ExperimentComparisonChart.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ExperimentComparisonChart.mxml	(revision 15)
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Canvas
+	xmlns:s="library://ns.adobe.com/flex/spark"
+	xmlns:mx="library://ns.adobe.com/flex/mx"
+	xmlns:cp="gssim.gssimstudio.editor.charts.com.connectedpixel.charts.*" 
+	xmlns:c="gssim.gssimstudio.editor.charts.components.*"
+	xmlns:fx="http://ns.adobe.com/mxml/2009"
+	width="100%" creationComplete="init()"
+	height="100%" xmlns:charts="com.iwobanas.charts.*" xmlns:data="gssim.gssimstudio.editor.charting.data.*" xmlns:charts1="gssim.gssimstudio.editor.charts.*" 
+>
+	<fx:Metadata>
+		[ResourceBundle("Charts")]
+	</fx:Metadata>
+	
+	<fx:Declarations>
+		<fx:Object id="service"/>
+		
+		<s:ArrayCollection id="metricTypeAC">
+			<fx:Object label="{resourceManager.getString('Charts', 'MeanType')}" type="mean"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'StdevType')}" type="stdev"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'VarType')}" type="variance"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'MinType')}" type="min"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'MaxType')}" type="max"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'CountType')}" type="count"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'SumType')}" type="sum"/>
+		</s:ArrayCollection>
+		
+		<s:ArrayCollection id="chartTypeAC">
+			<fx:Object label="{resourceManager.getString('Charts', 'ColumnType')}" type="column"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'LinearType')}" type="linear"/>
+		</s:ArrayCollection>
+		
+		<s:ArrayCollection id="xAxisTypeAC">
+			<fx:Object label="{resourceManager.getString('Charts', 'ExperimentType')}" type="experiment"/>
+			<fx:Object label="{resourceManager.getString('Charts', 'ParameterType')}" type="parameter"/>
+		</s:ArrayCollection>
+	</fx:Declarations>
+
+	<fx:Script>
+	    <![CDATA[
+			import gssim.gssimstudio.editor.script.command.SaveToPNGCommand;
+			
+			import mx.charts.AxisRenderer;
+			import mx.charts.chartClasses.AxisLabelSet;
+			import mx.charts.chartClasses.IAxis;
+			import mx.charts.series.ColumnSeries;
+			import mx.charts.series.LineSeries;
+			import mx.collections.ArrayCollection;
+			import mx.controls.Alert;
+			import mx.controls.HScrollBar;
+			import mx.controls.Label;
+			import mx.controls.scrollClasses.ScrollBar;
+			import mx.events.DragEvent;
+			import mx.events.FlexEvent;
+			import mx.events.ResizeEvent;
+			import mx.events.ScrollEvent;
+			import mx.events.SliderEvent;
+			import mx.graphics.SolidColor;
+			import mx.messaging.management.ObjectInstance;
+			import mx.rpc.events.ResultEvent;
+			import mx.utils.ObjectUtil;
+	
+			[Bindable]
+			public var experiments : ArrayCollection;
+			[Bindable]
+			public var compId : String; //id of this component in model array
+			
+			[Bindable]
+			protected var date : Date = new Date();
+			
+			[Bindable]
+			protected var parameterTypes : ArrayCollection =
+				new ArrayCollection( [
+					{parameter : "Delayed tasks", selected : false},
+					{parameter : "Energy usage", selected : false},
+					{parameter : "Failed requests (tasks)", selected : false},
+					{parameter : "Makespan", selected : false},
+					{parameter : "Resources queue length", selected : false},
+					{parameter : "Resources reservation load", selected : false},
+					{parameter : "Resources total load", selected : false},
+					{parameter : "Task completion time", selected : false},
+					{parameter : "Task execution time", selected : false},
+					{parameter : "Task flow time", selected : false},
+					{parameter : "Task lateness", selected : false},
+					{parameter : "Task start time", selected : false},
+					{parameter : "Task tardiness", selected : false},
+					{parameter : "Task waiting time", selected : false}
+					]);
+			
+			private function selectedOnly(item:Object, idx:uint, arr:Array):Boolean {
+				return item.selected;
+			}
+			
+			private function saveAsPNG() : void
+			{
+				var k : SaveToPNGCommand = new SaveToPNGCommand(chartCanvas);
+				k.execute();
+			}
+			
+			protected function init():void
+			{
+				getAvailableExperiments();
+			}
+					
+			public function plot() : void
+			{
+				switch(xAxisTypeComboBox.selectedItem.type)
+				{
+					case "experiment":
+						plotExperimentOnX();
+						break;
+					case "parameter":
+						plotParameterOnX();
+						break;
+					default:
+						break;
+				}
+			}
+			
+			protected function plotExperimentOnX() : void
+			{
+				var array : ArrayCollection = new ArrayCollection();
+				for (var i : int = 0; i < experiments.length; i++)
+				{
+					array.addItem(experiments[i].pk);
+				}
+				
+				var tArr:Array = parameterTypes.source.filter(selectedOnly);
+				var params : ArrayCollection = new ArrayCollection();
+				var series : Array = new Array();
+				for (var j : int = 0; j < tArr.length; j++)
+				{
+					params.addItem(tArr[j].parameter + " " + metricTypeComboBox.selectedItem.type);
+				}
+				
+				parentApplication.addModelUpdatedSingleCallbacks(
+					service.getComparisonFromDb(array,params)
+						, updateExperimentChart);
+			}
+			
+			protected function plotParameterOnX() : void
+			{
+				var array : ArrayCollection = new ArrayCollection();
+				for (var i : int = 0; i < experiments.length; i++)
+				{
+					array.addItem(experiments[i].pk);
+				}
+				
+				var tArr:Array = parameterTypes.source.filter(selectedOnly);
+				var params : ArrayCollection = new ArrayCollection();
+				var series : Array = new Array();
+				for (var j : int = 0; j < tArr.length; j++)
+				{
+					params.addItem(tArr[j].parameter + " " + metricTypeComboBox.selectedItem.type);
+				}
+				
+				parentApplication.addModelUpdatedSingleCallbacks(
+					service.getCategoryComparisonFromDb(array,params)
+					, updateParameterChart);
+			}
+			
+			protected function updateExperimentChart(event : ResultEvent) : void
+			{
+				var tArr:Array = parameterTypes.source.filter(selectedOnly);
+				var classRef : Class;
+				switch(chartTypeComboBox.selectedItem.type)
+				{
+					case "column":
+						classRef = ColumnSeries;
+						break;
+					case "linear":
+						classRef = LineSeries;
+						break;
+					default:
+						classRef = ColumnSeries;
+						break;
+				}
+				var serie : Object = new classRef();
+				resourceViewer.series = [serie]
+				for (var j : int = 0; j < tArr.length; j++)
+				{
+					serie.xField = "experiment";
+					serie.filterData = false;
+					serie.yField = tArr[j].parameter + " " + metricTypeComboBox.selectedItem.type;
+					serie.name = tArr[j].parameter;
+					serie.displayName = serie.name;
+					resourceViewer.series[j] = serie;
+					serie = new classRef();
+				}
+				date = new Date();
+				Alert.show(parentApplication.gsSimStudioModel.comparisonComponents[compId].xAxisLabels.toString());
+			}
+			
+			protected function updateParameterChart(event : ResultEvent) : void
+			{
+				var tArr:Array = experiments.source;
+				var classRef : Class;
+				switch(chartTypeComboBox.selectedItem.type)
+				{
+					default:
+						classRef = ColumnSeries;
+						break;
+				}
+				var serie : Object = new classRef();
+				resourceViewer.series = [serie]
+				for (var j : int = 0; j < tArr.length; j++)
+				{
+					serie.xField = "experiment";
+					serie.filterData = false;
+					serie.yField = tArr[j].pk;
+					serie.name = tArr[j].name;
+					serie.displayName = serie.name;
+					resourceViewer.series[j] = serie;
+					serie = new classRef();
+				}
+				date = new Date();
+			}
+			
+			protected function labelProvider(item : Object) : String
+			{
+				return item.name + " ["+ item.folder + "]";
+			}
+			
+			protected function expFilterFunction(it:Object):Boolean
+			{
+				for each (var item : Object in experiments)
+				{
+					if (item.pk == it.pk) return false;
+				}
+				return true;
+			}
+			
+			protected function getAvailableExperiments() : void
+			{
+				var array : ArrayCollection = parentApplication.archiveViewer.getExperimentNames();
+				array.filterFunction = expFilterFunction;
+				array.refresh();
+				availableList.dataProvider = array;
+				availableList.visible = true;
+			}
+			
+			protected function removeItem(index : Number) : void
+			{
+				if (index >= 0 && experiments.length > index) 
+					availableList.dataProvider.addItem(experiments.removeItemAt(index));
+			}
+			
+			protected function collapse(value : Boolean) : void
+			{
+				configPanel.visible = value;
+			}
+			
+			protected function prepareXLabel(item:Object, prevValue:Object, axis:CategoryAxis, categoryItem:Object) : String
+			{
+				if (categoryItem.label != null)
+					return categoryItem.label.toString();;
+				return item.toString();
+			}
+
+	    ]]>
+	</fx:Script>
+	
+	<fx:Style source="/gssim/gssimstudio/editor/assets/css/charts.css"/>
+	
+	<mx:VBox width="100%" height="100%">
+		<mx:Canvas  width="100%">
+			<mx:HBox width="100%" id="configPanel" includeInLayout="{configPanel.visible}">
+				<mx:VBox width="200">
+					<mx:Label text="{resourceManager.getString('Charts', 'AvailableExperiments')}" width="100%" />
+					<mx:List id="availableList" dragEnabled="true" dragMoveEnabled="true" width="100%" />
+				</mx:VBox>
+				<mx:VBox width="200">
+					<mx:Label text="{resourceManager.getString('Charts', 'IncludedExperiments')}" width="100%" />
+					<mx:List dataProvider="{experiments}" id="expList" dropEnabled="true" width="100%" />
+					<mx:Button label="Remove item" click="removeItem(expList.selectedIndex)"/>
+				</mx:VBox>
+				<mx:VBox width="100%">
+					<mx:List id="parameterList" dataProvider="{parameterTypes}" labelField="parameter">
+						<mx:itemRenderer>
+							<fx:Component>
+								<mx:CheckBox selectedField="selected" label="{data.parameter}"
+											 change="onChange(event);">
+									<fx:Script>
+										<![CDATA[
+											private function onChange(evt:Event):void {
+												data.selected = !data.selected;
+											}
+										]]>
+									</fx:Script>
+								</mx:CheckBox>
+							</fx:Component>
+						</mx:itemRenderer>
+					</mx:List>
+				</mx:VBox>
+			</mx:HBox>
+			<mx:VBox right="0">
+				<mx:HBox>
+					<mx:Button label="{resourceManager.getString('Charts', 'Collapse')}" click="collapse(false);" visible="{configPanel.visible}" includeInLayout="{configPanel.visible}"/>
+					<mx:Button label="{resourceManager.getString('Charts', 'UnCollapse')}" click="collapse(true);" visible="{!configPanel.visible}" includeInLayout="{!configPanel.visible}"/>
+					<mx:Button label="PNG" click="saveAsPNG();"/>
+				</mx:HBox>
+				<mx:VBox visible="{configPanel.visible}" includeInLayout="{configPanel.visible}">
+					<mx:HBox>
+						<mx:Label text="{resourceManager.getString('Charts', 'XAxisParameterLabel')}"/>					
+						<mx:ComboBox dataProvider="{xAxisTypeAC}" id="xAxisTypeComboBox"/>	
+					</mx:HBox>
+					<mx:HBox visible="{xAxisTypeComboBox.selectedItem.type == 'experiment'}"
+							 includeInLayout="{xAxisTypeComboBox.selectedItem.type == 'experiment'}">
+						<mx:Label text="{resourceManager.getString('Charts', 'ChartTypeLabel')}"/>
+						<mx:ComboBox dataProvider="{chartTypeAC}" id="chartTypeComboBox"/>
+					</mx:HBox>
+					<mx:HBox>
+						<mx:Label text="{resourceManager.getString('Charts', 'CharacteristicType')}"/>
+						<mx:ComboBox dataProvider="{metricTypeAC}" id="metricTypeComboBox"/>	
+					</mx:HBox>
+					<mx:Button label="{resourceManager.getString('Charts', 'Plot')}" click="plot();"/>
+				</mx:VBox>
+			</mx:VBox>
+		</mx:Canvas>
+		<mx:Canvas width="100%" height="100%" id="chartCanvas">
+			<mx:VBox width="100%" height="100%">
+				<mx:Label text="{resourceManager.getString('Charts', 'ComparisonTitle')}" width="100%" styleName="title"/>
+				<mx:Label text="{resourceManager.getString('Charts', 'Created')} {resourceManager.getString('Charts', 'Day')} {date}" width="100%" styleName="subtitle"/>
+				<mx:HBox width="100%" height="100%">
+					<mx:VBox width="100%" height="100%">
+						
+						<mx:ColumnChart 
+							id="resourceViewer" height="100%" width="100%"
+							paddingRight="5" paddingLeft="5"
+							dataProvider="{parentApplication.gsSimStudioModel.comparisonComponents[compId].dataList}"
+							>
+							<mx:horizontalAxis>
+								<mx:CategoryAxis 
+									id="hAxis" 
+									title="{resourceManager.getString('Charts', 'Experiment')}"
+									categoryField="experiment" labelFunction="prepareXLabel"
+									/>
+							</mx:horizontalAxis>
+						</mx:ColumnChart>
+						<!--~~~~~~~~~~ END OF RESOURCE VIEWER ~~~~~~~~~~-->
+						
+					</mx:VBox>
+				</mx:HBox>
+			</mx:VBox>
+			<mx:Legend dataProvider="{resourceViewer}" right="5" top="5" />
+		</mx:Canvas>
+	</mx:VBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ScheduleViewer.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ScheduleViewer.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ScheduleViewer.mxml	(revision 15)
@@ -0,0 +1,619 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Canvas
+	xmlns:v="gssim.gssimstudio.editor.charts.scheduling.*" 
+	xmlns:mx="http://www.adobe.com/2006/mxml"
+	xmlns:ssl="gssim.gssimstudio.editor.charts.smoothScrollingList.*"
+	xmlns:c="gssim.gssimstudio.editor.charts.components.*"
+	creationComplete="onCreationComplete()"
+	
+	mouseDown="onMouseDown(event)" 
+	mouseMove="onMouseMove(event)" 
+	mouseUp="onMouseUp(event)"
+	
+	width="100%"
+	height="100%"
+>
+
+	<mx:Script>
+      <![CDATA[
+      	import mx.events.SliderEvent;
+      	
+      	import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.ColoredScheduleEntry;
+		import gssim.gssimstudio.editor.charts.scheduling.samples.ScheduleData;
+		import gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.SimpleScheduleEntry;
+		import gssim.gssimstudio.editor.charts.scheduling.util.DateUtil;
+		import mx.collections.ArrayCollection;
+		import mx.controls.Alert;
+		import mx.events.ScrollEvent;
+		import mx.events.ScrollEventDirection;       
+		 
+		public var inputData : String;
+		/**
+		 * Value represents the width and height of every zoom button.
+		 */
+		[Bindable]
+		public var zoomButtonSize : Number = 20;
+		[Bindable]
+		private var dataProvider : ArrayCollection;     
+		[Bindable]
+		private var startDate : Date;
+		[Bindable]
+		private var endDate : Date;
+		[Bindable]
+		private var zoomHorizontal : Number;
+		[Bindable]
+		private var scheduleViewerWidth : Number = 600;
+		[Bindable]
+		private var proclineProvider : ArrayCollection = new ArrayCollection();
+		    
+		public var procNumber : int = 10;
+		public var tasksNumber : int = 5;
+		    
+		private function onCreationComplete() : void
+		{
+			inputData = "0;0;-1;compRes1;2;1225670321;1225684721;1225684800;1225666800;1225666801;17912;3521;14400;0;3521;17921;3520;1;-79;0;1224666800;1225684800;[1@compRes1, 2@compRes1]\n1;0;-1;compRes1;1;1225666801;1225695601;1225699200;1225666800;1225666801;28801;1;28800;0;1;28800;0;1;-3599;0;122566800;1225699200;[0@compRes1]"
+			
+		   setTimeframe();
+		   initRandomDataProvider();
+		    
+		   setZoomHorizontal(101);
+		   setZoomVertical(101);
+		}
+		 
+		/**
+		 * Sets zoomSliderHorizontal's value and calls onZoom event handler.
+		 **/
+		private function setZoomHorizontal(value : Number) : void
+		{
+			zoomSliderHorizontal.value = value;
+			hZoom(zoomSliderHorizontal.value);
+		}
+		
+		/**
+		 * Sets zoomSliderVertical's value and calls onZoom event handler.
+		 **/
+		private function setZoomVertical(value : Number) : void
+		{
+			//
+		}
+		
+		/**
+		 * Sets xPosition of scroll bar in Timeline component 
+		 * and calls onScrollTimeline event handler.
+		 **/
+		private function setTimeline(value : Number):void
+		{
+			timeline.xPosition = value;
+			onScrollTimeline(timeline.xPosition);
+		}
+		
+		private function setTimeframe() : void
+		{
+		   startDate = DateUtil.clearTime( new Date() );
+		   endDate = getEndDate( startDate );
+		}
+		
+		private function getEndDate( startDate : Date ) : Date
+		{
+		   var duration : Number = DateUtil.DAY_IN_MILLISECONDS * 1;
+		   var endDate : Date = new Date( startDate.getTime() + duration );
+		   return endDate;
+		}
+		
+		private function ParseInputData(data : String) : Array
+		{
+			var resultMatrix : Array = new Array();
+			var rows : Array = data.split(/\n/);
+			for (var i : int = 0; i < rows.length; ++i)
+				if (rows[i] != "")
+					resultMatrix.push((rows[i] as String).split(/;/));
+			
+			return resultMatrix;
+		}
+		
+		// out
+		/**
+		 * Compare two dates.
+		 * Returns:
+		 * 		True, if d1 is earlier,
+		 * 		False, otherwise.
+		 */
+		private function compareDates(d1 : Date, d2 : Date) : Boolean
+		{
+			if (d1.getTime() < d2.getTime())
+				return true;
+			else
+				return false;
+		}
+		
+		// out
+		private function min(d1 : Date, d2 : Date) : Date
+		{
+			if (compareDates(d1, d2))
+				return d1;
+			else
+				return d2;
+		}
+		
+		// out
+		private function max(d1 : Date, d2 : Date) : Date
+		{
+			if (compareDates(d1, d2))
+				return d2;
+			else
+				return d1;
+		}
+		
+		private function initDataProvider() : void
+		{
+			if (inputData == "" || inputData == null)
+			{
+				throw new Error("No input data");
+			}
+			else
+			{
+				startDate = new Date(0);
+				endDate = new Date(0);
+				
+				var procNames : Array = new Array();
+				dataProvider = new ArrayCollection();
+				
+				var matrix : Array = ParseInputData(inputData);
+				
+				for (var i : int = 0; i < matrix.length; ++i)
+				{
+					var currRow : int = procNames.indexOf(matrix[i][3]);
+					
+					if (currRow < 0)
+					{
+						procNames.push(matrix[i][3]);
+						dataProvider.addItem(new ArrayCollection());
+						
+						currRow = dataProvider.length - 1;
+					}
+					
+					var proc : Array = matrix[i];
+					
+					// start date
+					var entry : ColoredScheduleEntry = new ColoredScheduleEntry();
+					entry.startDate = new Date(parseInt(proc[5]));
+					// end date
+					entry.endDate = new Date(parseInt(proc[6]));
+					// color
+					entry.backgroundColor = 0x999999 + randomInt( 0x777777 );
+					 
+					// startDate/endDate
+					if (i == 0)
+					{
+						startDate = entry.startDate;
+						endDate = entry.endDate;
+					}
+					else
+					{
+						startDate = min(startDate, entry.startDate);
+						endDate = max(endDate, entry.endDate);
+					}
+					dataProvider[currRow].addItem(entry);
+				}
+				proclineProvider = new ArrayCollection(procNames);
+			}
+		}
+
+		private function randomInt( max : Number ) : Number
+		{
+			return Math.floor( Math.random() * max );
+		}
+		
+		/**
+		 * Initializes dataPrivider based on string variable "inputData",
+		 * which contains data about processors and tasks in specified format.
+		 **/
+		private function initRandomDataProvider() : void
+		{
+			dataProvider = (new ScheduleData()).createRowsOfRandomColoredEntries(procNumber, tasksNumber);
+		   	//dataProvider = new ScheduleData().createRandomColoredScheduleEntries( 100 );
+		   
+		   	var procNames : Array = new Array();
+		   	for (var i : int = 0; i < procNumber; ++i)
+		   		procNames.push("P" + (i + 1));
+		   	proclineProvider = new ArrayCollection(procNames);
+		}
+		
+		private function onZoomHorizontal(event : SliderEvent) : void
+		{
+			hZoom(event.value);
+		}
+		
+		private function hZoom(value : Number) : void
+		{
+			if (value == 0)
+			{
+				value = 1;
+				zoomSliderHorizontal.value = 1;
+			}
+			zoomHorizontal = value;
+		}
+		
+		private function onZoomVertical(event : SliderEvent) : void
+		{
+			vZoom(event.value);
+		}
+		
+		private function vZoom(value : Number) : void
+		{
+			if (value == 0)
+			{
+				value = 1;
+				zoomSliderHorizontal.value = 1;
+			}
+			scheduleViewer.rowHeight = value;
+		}
+		
+		private function onScrollScheduleViewer(event : ScrollEvent) : void
+		{
+			if (event.direction == ScrollEventDirection.HORIZONTAL)
+				timeline.xPosition = event.position;
+		}
+		
+		private function scrollList(event : ScrollEvent) : void
+		{
+			if (event.direction == ScrollEventDirection.VERTICAL )
+			{
+				procline.verticalScrollPosition = event.position;      
+			}
+		}
+		
+		/******************
+		 *	   Zooming 
+		 *****************/
+		
+		protected const scrollBarWidth : int = 16; 
+		private var selectionStarted : Boolean = false;
+		private var selectionInitialized : Boolean = false;
+		private var startPosition : Point;
+		private var startPositionInside : Point;
+		
+		private function onMouseDown(event:MouseEvent):void
+		{
+			if (scheduleViewer.contentMouseX >= 0 && scheduleViewer.contentMouseY >= 0 &&
+				scheduleViewer.contentMouseX <= scheduleViewer.width - scrollBarWidth &&
+				scheduleViewer.contentMouseY <= scheduleViewer.height)
+			{
+		    	if (event.buttonDown)
+		    	{
+		    		trace("left down (" + event.stageX.toString() + ", " + event.stageY.toString() + ")");
+		    		trace("[local] (" + event.localX + ", " + event.localY + ")");
+		    		selectionInitialized = true;
+		    		startPosition = new Point(event.stageX - this.x, event.stageY - this.y);
+		    		startPositionInside = new Point(scheduleViewer.contentMouseX, scheduleViewer.contentMouseY);
+		    		
+		    		selectionBox.x = startPositionInside.x;
+		    		selectionBox.y = startPositionInside.y;
+		    		selectionBox.width = 0;
+		    		selectionBox.height = 0;
+		    	}
+			}
+		}
+		
+		private function onMouseMove(event:MouseEvent):void
+		{
+			if (scheduleViewer.contentMouseX >= 0 && scheduleViewer.contentMouseY >= 0 &&
+				scheduleViewer.contentMouseX <= scheduleViewer.width - scrollBarWidth &&
+				scheduleViewer.contentMouseY <= scheduleViewer.height)
+			{
+				if (selectionInitialized)
+				{
+					selectionStarted = true;
+					selectionBox.visible = true;
+					
+					var localX : int = event.stageX - this.x;
+					var localY : int = event.stageY - this.y;
+					
+					selectionBox.width = Math.abs(localX - startPosition.x);
+					selectionBox.height = Math.abs(localY - startPosition.y);
+					
+					if (localX - startPosition.x > 0 && localY - startPosition.y < 0)
+					{
+						selectionBox.y = scheduleViewer.contentMouseY;
+					}
+					else if (localX - startPosition.x < 0 && localY - startPosition.y > 0)
+					{
+						selectionBox.x = scheduleViewer.contentMouseX;
+					}
+					else if (localX - startPosition.x < 0 && localY - startPosition.y < 0)
+					{
+						selectionBox.x = scheduleViewer.contentMouseX;
+						selectionBox.y = scheduleViewer.contentMouseY;
+					}
+					// else it's ok
+				}
+			}
+		}
+		
+		private function onMouseUp(event:MouseEvent):void
+		{
+			onTimelineMouseUp();
+			onProclineMouseUp();
+			
+			if (selectionInitialized)
+				selectionInitialized = false;
+			
+			if (selectionStarted)
+			{
+				selectionStarted = false;
+				selectionBox.visible = false;
+				
+				if (scheduleViewer.contentMouseX < startPositionInside.x)
+					startPositionInside.x = scheduleViewer.contentMouseX;
+				if (scheduleViewer.contentMouseY < startPositionInside.y)
+					startPositionInside.y = scheduleViewer.contentMouseY;
+					
+				if (selectionBox.width > 10 && selectionBox.height > 10)
+				{
+					horizontalZoom();
+			   		verticalZoom();
+				}
+				selectionBox.width = 0;
+				selectionBox.height = 0;
+			}
+		}
+		
+		private function horizontalZoom() : void
+		{
+			var scrollPositionHorizontal : Number = (timeline.xPosition + startPositionInside.x) / scheduleViewer.navigator.contentWidth;
+			var targetWidth : Number = scheduleViewer.navigator.contentWidth * scheduleViewer.width / selectionBox.width;
+			setZoomHorizontal(100 * Math.sqrt(targetWidth / scheduleViewer.width));
+			scheduleViewer.xPosition = scrollPositionHorizontal * targetWidth;
+		}
+		
+		private function verticalZoom() : void
+		{
+			var contentHeight : int = procNumber * scheduleViewer.rowHeight;
+			var scrollPositionVertical : Number = (procline.yPosition + startPositionInside.y) / contentHeight;
+			var targetHeight : Number = contentHeight * scheduleViewer.height / selectionBox.height;
+			//setZoomVertical(100 * Math.sqrt(targetHeight / scheduleViewer.height));
+			   		
+			scheduleViewer.rowHeight = targetHeight / procNumber;
+			procline.rowHeight = targetHeight / procNumber;
+			   		
+			scheduleViewer.yPosition = scrollPositionVertical * targetHeight;
+			procline.yPosition = scheduleViewer.yPosition;
+		}
+		
+		/**
+		 * Procedura zoomuje na podstawie selectionBox'a o rozmiarach okreÅlonych przez parametr.
+		 *	Parametr jest stosunkiem docelowego rozmiaru do rozmiaru aktualnego ciaÅa wykresu. 
+		 **/
+		private function rectZoom(zoom:Number):void
+		{
+			// setting selectionBox
+			selectionBox.width = zoom * scheduleViewer.width;
+			selectionBox.height = zoom * scheduleViewer.height;
+		 	selectionBox.x = ((scheduleViewer.width - selectionBox.width - scrollBarWidth) / 2) + scheduleViewer.xOffset;
+		 	selectionBox.y = ((scheduleViewer.height - selectionBox.height) / 2) + scheduleViewer.yOffset + timeline.height + parseInt(container.getStyle("verticalGap"));
+		 	// zooming
+		 	var scrollPositionHorizontal : Number = (timeline.xPosition + selectionBox.x - scheduleViewer.xOffset) / scheduleViewer.navigator.contentWidth;
+			var targetWidth : Number = scheduleViewer.navigator.contentWidth * scheduleViewer.width / selectionBox.width;
+			setZoomHorizontal(100 * Math.sqrt(targetWidth / scheduleViewer.width));
+			scheduleViewer.xPosition = scrollPositionHorizontal * targetWidth;
+			
+			
+		 	var contentHeight : int = procNumber * scheduleViewer.rowHeight;
+			var scrollPositionVertical : Number = (procline.yPosition + + selectionBox.y - scheduleViewer.yOffset) / contentHeight;
+			var targetHeight : Number = contentHeight * scheduleViewer.height / selectionBox.height;
+			//setZoomVertical(100 * Math.sqrt(targetHeight / scheduleViewer.height));
+			   		
+			scheduleViewer.rowHeight = targetHeight / procNumber;
+			procline.rowHeight = targetHeight / procNumber;
+			   		
+			scheduleViewer.yPosition = scrollPositionVertical * targetHeight;
+			procline.yPosition = scheduleViewer.yPosition;
+		 	// reseting
+		 	selectionBox.width = 0;
+		 	selectionBox.height = 0;
+		}
+		 
+		private var position : Number;
+		 
+		/**********************
+		 * Timeline scrolling
+		 **********************/
+		 
+		private var scrollingTimeline : Boolean = false;
+          
+		private function onScrollTimeline( position : Number ) : void
+		{
+			scrollingTimeline = true;
+			this.position = position;
+		}
+
+		private function onTimelineMouseUp() : void
+		{
+			if (scrollingTimeline)
+				scheduleViewer.xPosition = position;
+			scrollingTimeline = false;
+		}
+		
+		/**********************
+		 * Procline scrolling
+		 *********************/
+		 
+		private var scrollingProcline : Boolean = false;
+		
+		private function onScrollProcline(position : Number) : void
+		{
+			scrollingProcline = true;
+			this.position = position;
+		}
+		
+		private function onProclineMouseUp() : void
+		{
+			if (scrollingProcline)
+				scheduleViewer.yPosition = position;
+			scrollingProcline = false;
+		}
+		
+		/***
+		 * Generating random data
+		 * 
+		 * procNum - number of processors
+		 * tasksNum - number of tasks per every processor
+		 */
+		public function generateRandom(procNum : int, tasksNum : int) : void
+        {
+         	if (isNaN(procNum) || isNaN(tasksNum) || procNum <= 0 || tasksNum <= 0) 
+         	{
+         		Alert.show("Enter valid number values greater than 0", "Error");
+         	}
+         	else
+         	{
+         		procNumber = procNum;
+         		tasksNumber = tasksNum;
+         		initDataProvider();
+         	}
+        }
+        
+        private function minNum(x1 : Number, x2 : Number) : Number
+        {
+        	if (x1 < x2)
+        		return x1;
+        	else
+        		return x2;
+        }
+        
+        private function maxNum(x1 : Number, x2 : Number) : Number
+        {
+        	if (x1 > x2)
+        		return x1;
+        	else
+				return x2;
+		}
+      ]]>
+	</mx:Script>
+	
+
+	<mx:Style source="/gssim/gssimstudio/editor/assets/css/charts.css"/>
+
+	<mx:VBox width="100%" height="100%" verticalGap="1">
+		<mx:Label text="Gantt chart for Grid Scheduling Simulator" width="100%" styleName="title"/>
+		<mx:Label text='created for "Simulation1" at Mon Jun 22 13:41:57 CET 2010' width="100%" styleName="subtitle"/>
+		<mx:Spacer height="10"/>
+		
+		<mx:HBox width="100%" height="100%" verticalGap="0">
+			<mx:VBox verticalGap="8" width="90" height="100%">
+				<mx:Spacer height="{ timeline.height + hAxisTitle.height }"/>
+				
+				<mx:HBox width="100%" height="100%" horizontalGap="0">
+					<!-- vertical axis title -->
+			        <mx:Canvas 
+			        	id="vAxisTitleContainer" 
+			        	width="30" 
+			        	height="100%"
+			        >
+		                <mx:Label 
+		                	x="20" 
+		                	y="-10" 
+		                	text="Tasks"  
+		                	rotation="90" 
+		                	styleName="verticalAxisTitle" 
+		                	width="{vAxisTitleContainer.height}" 
+		                	textAlign="center"
+		            	/>
+			        </mx:Canvas>
+			        
+			        <c:Procline 
+						id="procline" 
+						width="60" 
+						height="{ scheduleViewer.height }" 
+						rowHeight="{ scheduleViewer.rowHeight }" 
+						verticalScrollPolicy="auto" 
+						horizontalScrollPolicy="off" 
+						dataProvider="{ proclineProvider }" 
+						scroll="onScrollProcline(event.position)" 
+						mouseUp="onProclineMouseUp()"
+					/>
+				</mx:HBox>
+			</mx:VBox>
+			   
+			<mx:VBox id="container" width="100%" height="100%" verticalGap="1">
+				<mx:Label 
+					id="hAxisTitle" 
+                	text="Simulation time"  
+                	styleName="horizontalAxisTitle" 
+                	width="{ timeline.width }" 
+                	textAlign="center"
+                />
+				<v:Timeline 
+					id="timeline" 
+					width="100%" 
+					startDate="{ startDate }" endDate="{ endDate }" 
+					zoom="{ 10000 / zoomHorizontal }" 
+					scroll="onScrollTimeline( event.position );"  
+					borderThickness="0"
+					borderStyle="none"
+					liveScrolling="false"
+					mouseUp="onTimelineMouseUp()"
+				/>  
+				   
+				<mx:Canvas
+				 	width="100%" 
+				 	height="100%"
+				 	horizontalScrollPolicy="off"
+				 	verticalScrollPolicy="off">
+				<v:ScheduleViewer 
+					id="scheduleViewer"  
+					width="100%" height="100%" 
+					dataProvider="{ dataProvider }"    
+					startDate="{ startDate }" 
+					endDate="{ endDate }" 
+					zoom="{ 10000 / zoomHorizontal }" 
+					rowHeight="50" 
+					horizontalScrollPolicy="off" 
+					verticalScrollPolicy="off"  
+					entryRenderer="gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.renderers.ColoredSolidScheduleEntryRenderer"  
+					entryLayout="gssim.gssimstudio.editor.charts.scheduling.scheduleClasses.layout.SimpleLayout"     
+					pixelScroll="onScrollScheduleViewer( event );" 
+					pixelScrollEnabled="true"
+					itemScroll="scrollList(event)" 
+					mouseUp="onMouseUp(event)"
+					borderStyle="none" cachePolicy="on"
+				/>
+				<mx:Canvas id="selectionBox" styleName="selectionBox" visible="false"/>
+				</mx:Canvas>
+				
+				<mx:HBox width="100%" paddingTop="6">   
+					<mx:Spacer width="{ (scheduleViewer.width - zoomSliderHorizontal.width) / 2 }" />  
+					<c:HExtendedSlider 
+						id="zoomSliderHorizontal" 
+						width="150" 
+						minimum="0" 
+						maximum="100" 
+						value="100" 
+						liveDragging="false"
+						change="{onZoomHorizontal}"
+					/>
+				</mx:HBox>
+			</mx:VBox>
+			
+			<mx:VBox verticalGap="8" width="60" height="100%">
+				<mx:Spacer height="{ timeline.height + (scheduleViewer.height - zoomSliderVertical.height) / 2 }"/>
+				<c:VExtendedSlider 
+					id="zoomSliderVertical" 
+					height="150"
+					minimum="0" 
+					maximum="100" 
+					value="50" 
+					liveDragging="false" 
+					change="{ onZoomVertical }"
+				/>
+				
+				<mx:Spacer height="{(scheduleViewer.height - zoomSliderVertical.height) / 2 + zoomSliderHorizontal.height - zoomInIcon.height}" />
+				<mx:HBox width="100%" height="100%" horizontalGap="0">
+					<mx:Spacer width="100%"/>
+					<mx:Image id="zoomInIcon" source="/gssim/gssimstudio/editor/assets/icon/zoom_in_icon.gif" click="rectZoom(0.8)" toolTip="Zoom in"/>
+					<mx:Image id="zoomOutIcon" source="/gssim/gssimstudio/editor/assets/icon/zoom_out_icon.gif" click="rectZoom(1.2)" toolTip="Zoom out"/>
+				</mx:HBox>
+			</mx:VBox>
+		</mx:HBox>
+	</mx:VBox>
+</mx:Canvas>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ResourceChartModel.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ResourceChartModel.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/ResourceChartModel.as	(revision 15)
@@ -0,0 +1,21 @@
+package gssim.gssimstudio.editor.charts
+{
+import flash.events.EventDispatcher;
+import flash.utils.ByteArray;
+
+import mx.collections.ArrayCollection;
+
+	[Bindable]
+	[RemoteClass(alias = "gssim.gssimstudio.flex.app.editor.ResourceChartModel")]
+	public class ResourceChartModel {
+
+		public function ResourceChartModel() {
+		}
+
+		public var selectedResourceIndex : Number;
+		public var error:String;
+		public var resourceList:ArrayCollection;
+		public var resourceTimelineList:ArrayCollection;
+		public var experimentConfiguration:Object;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/StaticResourceChart.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/StaticResourceChart.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/StaticResourceChart.mxml	(revision 15)
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<MDIWindow xmlns="flexlib.mdi.containers.*"
+	xmlns:s="library://ns.adobe.com/flex/spark"
+	xmlns:mx="library://ns.adobe.com/flex/mx"
+	xmlns:cp="gssim.gssimstudio.editor.charts.com.connectedpixel.charts.*" 
+	xmlns:c="gssim.gssimstudio.editor.charts.components.*"
+	xmlns:fx="http://ns.adobe.com/mxml/2009"  width="600" height="400" title="{expName}:{resourceManager.getString('Charts', 'ResourceAllocationTitle')}"
+	xmlns:charts="com.iwobanas.charts.*" xmlns:data="gssim.gssimstudio.editor.charting.data.*" xmlns:charts1="gssim.gssimstudio.editor.charts.*" 
+>
+	
+	<fx:Metadata>
+		[ResourceBundle("Charts")]
+	</fx:Metadata>
+	<fx:Script>
+	    <![CDATA[
+			import gssim.gssimstudio.editor.script.command.SaveToPNGCommand;
+			
+			import mx.binding.utils.BindingUtils;
+			import mx.charts.AxisRenderer;
+			import mx.charts.chartClasses.AxisLabelSet;
+			import mx.collections.ArrayCollection;
+			import mx.controls.Alert;
+			import mx.controls.HScrollBar;
+			import mx.controls.Label;
+			import mx.controls.scrollClasses.ScrollBar;
+			import mx.events.FlexEvent;
+			import mx.events.ResizeEvent;
+			import mx.events.ScrollEvent;
+			import mx.events.SliderEvent;
+			import mx.messaging.management.ObjectInstance;
+			import mx.rpc.events.ResultEvent;
+			import mx.utils.ObjectUtil;
+	
+			[Bindable]
+			public var dataProvider : ArrayCollection;
+			[Bindable]
+			public var expName : String;
+			[Bindable]
+			public var resName : String;
+			
+			[Bindable]
+			protected var date : Date = new Date();
+
+			private function formatDate(value:Date, previousValue:Date, axis:DateTimeAxis) : String 
+			{      
+				var percent : Number = 1;//_hZoom / 100;
+				var limit : Number = (hAxis.maximum.getTime() - hAxis.minimum.getTime()) * 0.07;
+				
+				if (hAxis.maximum.getTime() - value.getTime() > limit)
+				{
+					var dateLabel : String = df.format(value);
+					var dateLabelLongSec : String = dateLabel;
+					if (value.seconds < 10)
+					{
+						dateLabelLongSec = dateLabel.substring(0, dateLabel.length - 1);
+						dateLabelLongSec += "0" + value.seconds;
+					}
+					return dateLabelLongSec;
+				}
+				else
+				{
+					return "";
+				}
+			}
+			
+			private function saveAsPNG() : void
+			{
+				var k : SaveToPNGCommand = new SaveToPNGCommand(fullChart);
+				k.execute();
+			}
+
+	    ]]>
+	</fx:Script>
+	
+	<fx:Style source="/gssim/gssimstudio/editor/assets/css/charts.css"/>
+
+	<fx:Declarations>
+		
+		<mx:SolidColorStroke id="s2" color="red" weight="2"/>
+		<mx:SolidColorStroke id="axisStroke" 
+			color="#224488" 
+			weight="8" 
+			alpha=".25"
+			caps="square"
+		/>
+		
+		<mx:SolidColor id="sc3" color="blue" alpha=".6"/>
+		
+		<mx:DateFormatter id="df" formatString="EEE, J:NN:S"/>
+		
+		<charts:ChartScroller chart="{resourceViewer}" chartMouseEnabled="true" verticalScrollEnabled="true" verticalZoomEnabled="true" />
+	
+	</fx:Declarations>
+		
+	<mx:Canvas width="100%" height="100%">
+		<mx:VBox width="100%" height="100%" verticalGap="1" id="fullChart">
+			<mx:Label text="{resourceManager.getString('Charts', 'ResourceAllocationTitle')}" width="100%" styleName="title"/>
+			<mx:Label text="{resourceManager.getString('Charts', 'CreatedFor')} {expName}:{resName} {resourceManager.getString('Charts', 'Day')} {date}" width="100%" styleName="subtitle"/>
+			<mx:HBox width="100%" height="100%">
+				<mx:VBox width="100%" height="100%">
+				
+					<!--~~~~~~~~~~ RESOURCE VIEWER ~~~~~~~~~~-->
+					<mx:AreaChart 
+						id="resourceViewer" height="100%" width="100%"
+				        paddingRight="5" paddingLeft="5"
+				        dataProvider="{dataProvider}"
+				    >
+				        <mx:horizontalAxis>
+				            <mx:DateTimeAxis 
+				            	id="hAxis" 
+				            	dataUnits="seconds" 
+				            	alignLabelsToUnits="false" 
+				            	labelFunction="formatDate" 
+								title="{resourceManager.getString('Charts', 'SimulationTime')}"
+				             />
+				        </mx:horizontalAxis>
+				
+				        <mx:verticalAxis>
+				            <mx:LinearAxis 
+				            	id="vAxis" 
+				            	baseAtZero="false" 
+				            	maximumLabelPrecision="1" 
+				            	autoAdjust="false" 
+								title="{resourceManager.getString('Charts', 'CPU')}"
+				            />
+				        </mx:verticalAxis>
+				
+						<mx:series>
+				            <mx:AreaSeries 
+								filterData="false"
+				            	yField="usage" 
+				            	xField="timestamp" 
+				            	form="step" 
+				            	areaFill="{sc3}" 
+				            />
+				        </mx:series>
+					     
+				    </mx:AreaChart>
+				    <!--~~~~~~~~~~ END OF RESOURCE VIEWER ~~~~~~~~~~-->
+				    
+				</mx:VBox>
+			</mx:HBox>
+		</mx:VBox>
+		<mx:HBox top="5" right="5">
+			<mx:Button label="PNG" click="saveAsPNG();"/>
+		</mx:HBox>
+	</mx:Canvas>
+</MDIWindow>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/iwobanas/NumericAxisHelper.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/iwobanas/NumericAxisHelper.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/iwobanas/NumericAxisHelper.as	(revision 15)
@@ -0,0 +1,95 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is: www.iwobanas.com code samples.
+
+The Initial Developer of the Original Code is Iwo Banas.
+Portions created by the Initial Developer are Copyright (C) 
+the Initial Developer. All Rights Reserved.
+
+Contributor(s):
+*/
+package com.iwobanas.charts
+{
+	import mx.charts.DateTimeAxis;
+	import mx.charts.LinearAxis;
+	import mx.charts.chartClasses.IAxis;
+	import mx.charts.chartClasses.NumericAxis;
+	
+	/**
+	 * The NumericAxisHelper class is an all-static class with methods for working with NumericAxis subclasses.
+	 * Currently NumericAxisHelper supports setting/getting numeric minimum/maximum on LinearAxis and DateTimeAxis.
+	 */
+	public class NumericAxisHelper
+	{
+		/**
+		 * Get minimum value for a given axis.
+		 */
+		public static function getMin(axis:IAxis):Number
+		{
+			if (axis is LinearAxis)
+			{
+				return LinearAxis(axis).minimum;
+			}
+			else if (axis is DateTimeAxis)
+			{
+				return DateTimeAxis(axis).minimum.time;
+			}
+			return NaN;
+		}
+		
+		/**
+		 * Get maxiumu value for a given axis.
+		 */
+		public static function getMax(axis:IAxis):Number
+		{
+			if (axis is LinearAxis)
+			{
+				return LinearAxis(axis).maximum;
+			}
+			else if (axis is DateTimeAxis)
+			{
+				return DateTimeAxis(axis).maximum.time;
+			}
+			return NaN;
+		}
+		
+		/**
+		 * Set minimum value for a given axis.
+		 */
+		public static function setMin(axis:IAxis, value:Number):void
+		{
+			if (axis is LinearAxis)
+			{
+				LinearAxis(axis).minimum = value;
+			}
+			else if (axis is DateTimeAxis)
+			{
+				DateTimeAxis(axis).minimum = new Date(value);
+			}
+		}
+		
+		/**
+		 * Set maximum value for a given axis.
+		 */
+		public static function setMax(axis:IAxis, value:Number):void
+		{
+			if (axis is LinearAxis)
+			{
+				LinearAxis(axis).maximum = value;
+			}
+			else if (axis is DateTimeAxis)
+			{
+				DateTimeAxis(axis).maximum = new Date(value);
+			}
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/collections/SubRangeArrayCollection.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/collections/SubRangeArrayCollection.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/collections/SubRangeArrayCollection.as	(revision 15)
@@ -0,0 +1,146 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Author: Joel May
+//  connectedpixel.com
+//  All code here not owned by Adobe Systems Incorporated is in the public domain.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package gssim.gssimstudio.editor.charts.com.connectedpixel.collections
+{
+	import flash.events.EventDispatcher;
+	
+	import mx.collections.IList;
+	import mx.events.CollectionEvent;
+	
+	// Wraps an ArrayCollection or XMLListCollection.  Creates a limited window
+	// into the wrapped collection.
+
+	[Inspectable(category="General", arrayType="Object")] // I don't know what this is for.
+	[Bindable("listChanged")] 
+	public class SubRangeArrayCollection extends EventDispatcher implements IList
+	{
+		private var inner:IList;	// Wrapped collection.
+		private var len:int;		// Externally visible array length.
+		private var iStart:int;		// Offset into the inner array for externally visible index 0.
+		
+		public function SubRangeArrayCollection(arr:IList, visibleLen:int, iStart:int=0)
+		{
+			this.inner = arr;		
+			this.len = visibleLen;
+			this.iStart = iStart;
+			
+			// Use weak ref.
+			arr.addEventListener(CollectionEvent.COLLECTION_CHANGE, onInnerCollectionChange, false, 0, true);
+		} 	
+		
+		private function onInnerCollectionChange(ev:CollectionEvent):void
+		{
+			// Bubble it up.
+			this.dispatchEvent(ev);
+		}
+		
+		////////////////////////////////////////
+		public function set firstIndexOffset(i:int):void
+		{
+			iStart = i;	
+			
+			var ev:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+			ev.kind = "refresh"
+			this.dispatchEvent(ev);
+		}
+		public function get firstIndexOffset():int
+		{
+			return iStart;
+		}
+		
+		// The externally visible length of the data. 
+		public function set maxLength(l:int):void
+		{
+			this.len = l;
+			
+			var ev:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+			ev.kind = "refresh"
+			this.dispatchEvent(ev);
+		}
+		public function get maxLength():int
+		{
+			return this.len;
+		}
+		
+		public function setRange(iFirstIndexOffset:int, nMaxLen:int):void
+		{
+			iStart = iFirstIndexOffset;	
+			this.len = nMaxLen;
+			var ev:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+			ev.kind = "refresh";
+			this.dispatchEvent(ev);
+		}
+		
+		////////////////////////////////////////
+		
+		public function addItemAt(item:Object, index:int):void
+		{
+			index += iStart;
+			inner.addItemAt(item,index);
+		}
+		
+		public function get length():int
+		{
+			return Math.min(len,inner.length);
+		}
+		
+		public function toArray():Array
+		{
+			var arr:Array = toArray();
+			var subArray:Array = new Array();
+			var n:int = this.length;
+			
+			for (var i:int = iStart ; i < n ; i++){
+				subArray.push(iStart+i);		
+			}
+			return subArray;
+		}
+		
+		public function getItemAt(index:int, prefetch:int=0.0):Object
+		{
+			return inner.getItemAt(iStart+index,prefetch);
+		}
+		
+		// BUGBUG: what does this do?
+		public function itemUpdated(item:Object, property:Object=null, oldValue:Object=null, newValue:Object=null):void
+		{
+			inner.itemUpdated(item,property,oldValue,newValue);
+		}
+		
+		public function removeAll():void
+		{
+			// BUGBUG: should this remove only items between iStart and iStart+len??
+			inner.removeAll();
+		}
+		
+		public function getItemIndex(item:Object):int
+		{
+			var i:int = inner.getItemIndex(item);
+			i -= iStart;
+			if (i < 0) return -1;
+			if (i >= len) return -1;
+			return i;
+		}
+		
+		public function setItemAt(item:Object, index:int):Object
+		{
+			return inner.setItemAt(item,iStart+index);
+		}
+		
+		public function removeItemAt(index:int):Object
+		{
+			return inner.removeItemAt(iStart+index);
+		}
+		
+		public function addItem(item:Object):void
+		{
+			inner.addItem(item);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollTrackSkin.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollTrackSkin.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollTrackSkin.as	(revision 15)
@@ -0,0 +1,45 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors.
+//  All Rights Reserved. The following is Source Code and is subject to all
+//  restrictions on such code as contained in the End User License Agreement
+//  accompanying this product.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Copied from mx.skins.halo.SliderThumbSkin and hacked by Joel May, connectedpixel.com, 
+// as part of the scrolling charts feature.
+
+// All hacking is related to making the scrollbar thinner so that it fits on the
+// Chart axis line.  This code has not been tested with the vertical axis, nor has 
+// it been tested with an altered axis line.   
+
+
+package gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins
+{
+	import mx.skins.halo.ScrollTrackSkin;
+	import mx.styles.StyleManager;
+	import mx.utils.ColorUtil;
+	import flash.display.GradientType;
+
+	public class AxisScrollTrackSkin extends ScrollTrackSkin
+	{
+		public function AxisScrollTrackSkin()
+		{
+			super();
+		}
+		
+		override protected function updateDisplayList(w:Number, h:Number):void
+		{
+			super.updateDisplayList(w, h);
+				
+			graphics.clear();
+			
+			// Draw clickable region, but make it not visible (alpha = 0)
+			graphics.beginFill(0xffffff,0.0);
+			graphics.drawRect(0,0,w,h);
+			graphics.endFill();
+		}
+	
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollArrowSkin.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollArrowSkin.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollArrowSkin.as	(revision 15)
@@ -0,0 +1,350 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors.
+//  All Rights Reserved. The following is Source Code and is subject to all
+//  restrictions on such code as contained in the End User License Agreement
+//  accompanying this product.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Copied from mx.skins.halo.SliderThumbSkin and hacked by Joel May, connectedpixel.com, 
+// as part of the scrolling charts feature.
+
+// All hacking is related to making the scrollbar thinner so that it fits on the
+// Chart axis line.  This code has not been tested with the vertical axis, nor has 
+// it been tested with an altered axis line.   
+
+package gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins
+{
+	import mx.skins.halo.ScrollArrowSkin;
+	import flash.display.GradientType;
+	import mx.styles.StyleManager;
+	import flash.display.Graphics;
+	import mx.skins.halo.HaloColors;
+	import mx.utils.ColorUtil;
+
+	public class AxisScrollArrowSkin extends ScrollArrowSkin
+	{
+		public function AxisScrollArrowSkin()
+		{
+			super();
+		}
+		//--------------------------------------------------------------------------
+		//
+		//  Class variables
+		//
+		//--------------------------------------------------------------------------
+	
+		/**
+		 *  @private
+		 */
+		private static var cache:Object = {};
+	
+		//--------------------------------------------------------------------------
+		//
+		//  Class methods
+		//
+		//--------------------------------------------------------------------------
+	
+		/**
+		 *  @private
+		 *  Several colors used for drawing are calculated from the base colors
+		 *  of the component (themeColor, borderColor and fillColors).
+		 *  Since these calculations can be a bit expensive,
+		 *  we calculate once per color set and cache the results.
+		 */
+		private static function calcDerivedStyles(themeColor:uint,
+												  borderColor:uint,
+												  fillColor0:uint,
+												  fillColor1:uint):Object
+		{
+			var key:String = HaloColors.getCacheKey(themeColor, borderColor,
+													fillColor0, fillColor1);
+			
+			if (!cache[key])
+			{
+				var o:Object = cache[key] = {};
+				
+				// Cross-component styles.
+				HaloColors.addHaloColors(o, themeColor, fillColor0, fillColor1);
+				
+				// ScrollArrow-specific styles
+				o.borderColorDrk1 = ColorUtil.adjustBrightness2(borderColor, -25);
+				o.borderColorDrk2 = ColorUtil.adjustBrightness2(borderColor, -50);
+			}
+			
+			return cache[key];
+		}
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden methods
+		//
+		//--------------------------------------------------------------------------
+	
+		/**
+		 *  @private
+		 */
+		override protected function updateDisplayList(w:Number, h:Number):void
+		{
+			super.updateDisplayList(w, h);
+	
+			// User-defined styles.
+			var backgroundColor:Number = getStyle("backgroundColor");
+			var borderColor:uint = getStyle("borderColor");
+			var fillAlphas:Array = getStyle("fillAlphas");
+			var fillColors:Array = getStyle("fillColors");
+			styleManager.getColorNames(fillColors);
+			var highlightAlphas:Array = getStyle("highlightAlphas");				
+			var themeColor:uint = getStyle("themeColor");
+			
+			var upArrow:Boolean = (name.charAt(0) == 'u');
+			
+			// Placeholder styles stub.
+			var arrowColor:uint = 0x111111;
+			
+			// Derived styles.
+			var derStyles:Object = calcDerivedStyles(themeColor, borderColor,
+													 fillColors[0], fillColors[1]);
+	
+			var horizontal:Boolean = parent &&
+									 parent.parent &&
+									 parent.parent.rotation != 0;
+			
+			var borderColors:Array;
+			if (upArrow && !horizontal)
+				borderColors = [ borderColor, derStyles.borderColorDrk1 ];
+			else
+				borderColors = [ derStyles.borderColorDrk1,
+								 derStyles.borderColorDrk2 ];
+	
+			//------------------------------
+			//  background
+			//------------------------------
+			
+			var g:Graphics = graphics;
+			g.clear();
+			
+			if (isNaN(backgroundColor))
+				backgroundColor = 0xFFFFFF;
+				
+			drawRoundRect(
+					0, 0, w, h, 0,
+					0xffffff, 0);
+			
+			// Opaque backing to force the scroll elements
+			// to match other components by default.
+			// Do not draw it for disabled arrows.
+			w *= 0.6;
+			
+			if (name.indexOf("Disabled") == -1)
+			{
+				drawRoundRect(
+					0, 0, w, h, 0,
+					backgroundColor, 1);
+			}                         
+			
+	
+			switch (name)
+			{
+				case "upArrowUpSkin":
+				{			
+					// shadow
+					if (!horizontal)
+					{
+						drawRoundRect(
+							1, h - 4, w - 2, 8, 0,
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [ 1, 0 ],
+							verticalGradientMatrix(1, h - 4, w - 2, 8),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: h-4, w: w - 2, h: 4, r: 0 });
+					}
+	
+					// intentionally fall through to the next case statement
+				}
+	
+				case "downArrowUpSkin":
+				{
+	   				var upFillColors:Array = [ fillColors[0], fillColors[1] ];
+	   				var upFillAlphas:Array = [ fillAlphas[0], fillAlphas[1] ];
+	
+					// border
+					drawRoundRect(
+						0, 0, w, h, 0,
+						borderColors, 1,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w, h) :
+						verticalGradientMatrix(0, 0, w, h),
+						GradientType.LINEAR, null, 
+						{ x: 1, y: 1, w: w - 2, h: h - 2, r: 0 });  
+	
+					// fill
+					drawRoundRect(
+						1, 1, w - 2, h - 2, 0,
+						upFillColors, upFillAlphas,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w - 2, h - 2) :
+						verticalGradientMatrix(0, 0, w - 2, h - 2 / 2));
+					
+					// top bighlight
+					drawRoundRect(
+						1, 1, w - 2, h - 2 / 2, 0,
+						[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w - 2, h - 2) :
+						verticalGradientMatrix(0, 0, w - 2, h - 2 / 2));
+					
+					break;
+				}
+				
+				case "upArrowOverSkin":
+				{                           
+					// shadow
+					if (!horizontal)
+					{
+						drawRoundRect(
+							1, h - 4, w - 2, 8, 0,
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [ 1, 0 ],
+							verticalGradientMatrix(1, h - 4, w - 2, 8),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: h-4, w: w - 2, h: 4, r: 0}); 
+					}
+	
+					// intentionally fall through to the next case statement
+				}
+				
+				case "downArrowOverSkin":
+				{
+					var overFillColors:Array;
+					if (fillColors.length > 2)
+						overFillColors = [ fillColors[2], fillColors[3] ];
+					else
+						overFillColors = [ fillColors[0], fillColors[1] ];
+	
+					var overFillAlphas:Array;
+					if (fillAlphas.length > 2)
+						overFillAlphas = [ fillAlphas[2], fillAlphas[3] ];
+	  				else
+						overFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
+	
+					// white backing to force the scroll elements
+					// to match other components by default
+					drawRoundRect(
+						0, 0, w, h, 0,
+						0xFFFFFF, 1);  
+	
+					// border
+					drawRoundRect(
+						0, 0, w, h, 0,
+						[ themeColor, derStyles.themeColDrk1 ], 1,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w, h) :
+						verticalGradientMatrix(0, 0, w, h),
+						GradientType.LINEAR, null, 
+						{ x: 1, y: 1, w: w - 2, h: h - 2, r: 0}); 
+	
+					// fill
+					drawRoundRect(
+						1, 1, w - 2, h - 2, 0,
+						overFillColors, overFillAlphas,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w - 2, h - 2) :
+						verticalGradientMatrix(0, 0, w - 2, h - 2)); 
+					
+					// top highlight
+					drawRoundRect(
+						1, 1, w - 2, h -2 / 2, 0,
+						[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w - 2, h - 2) :
+						verticalGradientMatrix(0, 0, w - 2, h - 2 / 2)); 
+					break;
+				}
+				
+				case "upArrowDownSkin":
+				{	
+					// shadow
+					if (!horizontal)
+					{
+						drawRoundRect(
+							1, h - 4, w - 2, 8, 0,
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [ 1, 0 ],
+							horizontal ?
+							horizontalGradientMatrix(1, h - 4, w - 2, 8) :
+							verticalGradientMatrix(1, h - 4, w - 2, 8),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: h - 4, w: w - 2, h: 4, r: 0 }); 
+					}
+						
+					// intentionally fall through to the next case statement
+				}
+	
+				case "downArrowDownSkin":
+				{
+					// border
+					drawRoundRect(
+						0, 0, w, h, 0,
+						[ themeColor, derStyles.themeColDrk1 ], 1,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w, h) :
+						verticalGradientMatrix(0, 0, w, h),
+						GradientType.LINEAR, null, 
+						{ x: 1, y: 1, w: w - 2, h: h - 2, r: 0 }); 
+	
+					// fill
+					drawRoundRect(
+						1, 1, w - 2, h - 2, 0,
+						[ derStyles.fillColorPress1,
+						  derStyles.fillColorPress2 ], 1,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w - 2, h - 2) :
+						verticalGradientMatrix(0, 0, w - 2, h - 2)); 
+					
+					// top highlight
+					drawRoundRect(
+						1, 1, w - 2, h -2 / 2, 0,
+						[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w - 2, h - 2) :
+						verticalGradientMatrix(0, 0, w - 2, h - 2 / 2)); 
+					break;
+				}
+				
+				default:
+				{
+					drawRoundRect(
+						0, 0, w, h, 0,
+						0xFFFFFF, 0);
+					
+					return;
+					break;
+				}
+			}
+	
+			// Draw up or down arrow
+			g.beginFill(arrowColor);
+			if (upArrow)
+			{
+				g.moveTo(w / 2, 6);
+				g.lineTo(2, h - 6);
+				//g.lineTo(w - 5, h - 6);
+				//g.lineTo(5, h - 6);
+				g.lineTo(w-2, h - 6);
+				g.lineTo(w / 2, 6);
+			}
+			else
+			{
+				g.moveTo(w / 2, h - 6);
+				//g.lineTo(w - 5, 6);
+				g.lineTo(2, 6);
+				//g.lineTo(5, 6);
+				g.lineTo(w-2, 6);
+				g.lineTo(w / 2, h - 6);
+			}
+			g.endFill();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollThumbSkin.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollThumbSkin.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/skins/AxisScrollThumbSkin.as	(revision 15)
@@ -0,0 +1,377 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors.
+//  All Rights Reserved. The following is Source Code and is subject to all
+//  restrictions on such code as contained in the End User License Agreement
+//  accompanying this product.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Copied from mx.skins.halo.SliderThumbSkin and hacked by Joel May, connectedpixel.com, 
+// as part of the scrolling charts feature.
+
+// All hacking is related to making the thumb thinner so that it fits on the
+// Chart axis line.  This code has not been tested with the vertical axis, nor has 
+// it been tested with an altered axis line.   
+
+package gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins
+{
+	import mx.skins.halo.ScrollThumbSkin;
+	import flash.display.GradientType;
+	import mx.styles.StyleManager;
+	import mx.skins.halo.HaloColors;
+	import mx.utils.ColorUtil;
+
+	public class AxisScrollThumbSkin extends ScrollThumbSkin
+	{
+		public function AxisScrollThumbSkin()
+		{
+			super();
+		}
+		//--------------------------------------------------------------------------
+		//
+		//  Class variables
+		//
+		//--------------------------------------------------------------------------
+	
+		/**
+		 *  @private
+		 */
+		private static var cache:Object = {};
+	
+		//--------------------------------------------------------------------------
+		//
+		//  Class methods
+		//
+		//--------------------------------------------------------------------------
+	
+		/**
+		 *  @private
+		 *  Several colors used for drawing are calculated from the base colors
+		 *  of the component (themeColor, borderColor and fillColors).
+		 *  Since these calculations can be a bit expensive,
+		 *  we calculate once per color set and cache the results.
+		 */
+		private static function calcDerivedStyles(themeColor:uint,
+												  borderColor:uint,
+												  fillColor0:uint,
+												  fillColor1:uint):Object
+		{
+			var key:String = HaloColors.getCacheKey(themeColor, borderColor,
+													fillColor0, fillColor1);
+			
+			if (!cache[key])
+			{
+				var o:Object = cache[key] = {}
+				
+				// Cross-component styles.
+				HaloColors.addHaloColors(o, themeColor, fillColor0, fillColor1);
+				
+				// ScrollArrowDown-specific styles.
+				o.borderColorDrk1 = ColorUtil.adjustBrightness2(borderColor, -50);
+			}
+			
+			return cache[key];
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function updateDisplayList(w:Number, h:Number):void
+		{
+			super.updateDisplayList(w, h);
+	
+			// User-defined styles.
+			var backgroundColor:Number = getStyle("backgroundColor");
+			var borderColor:uint = getStyle("borderColor");
+			var cornerRadius:Number = getStyle("cornerRadius");
+			var fillAlphas:Array = getStyle("fillAlphas");
+			var fillColors:Array = getStyle("fillColors");
+			styleManager.getColorNames(fillColors);
+			var highlightAlphas:Array = getStyle("highlightAlphas");				
+			var themeColor:uint = getStyle("themeColor");
+			
+			// Placeholder styles stub.
+			var gripColor:uint = 0x6F7777;
+			
+			// Derived styles.
+			var derStyles:Object = calcDerivedStyles(themeColor, borderColor,
+													 fillColors[0], fillColors[1]);
+													 
+			var radius:Number = Math.max(cornerRadius - 1, 0);
+			radius /= 2;
+			var cr:Object = { tl: 0, tr: radius, bl: 0, br: radius };
+			radius = Math.max(radius - 1, 0);
+			var cr1:Object = { tl: 0, tr: radius, bl: 0, br: radius };
+	
+			var horizontal:Boolean = parent &&
+									 parent.parent &&
+									 parent.parent.rotation != 0;
+	
+			if (isNaN(backgroundColor))
+				backgroundColor = 0xFFFFFF;
+			
+			graphics.clear();
+			
+			graphics.beginFill(0xff0000,0.0);
+			graphics.drawRect(-15,0,w,h);
+			//graphics.drawRect(0,0,w,h);
+			graphics.endFill();
+			
+			// Shrink the width to fit the thin axis line.
+			w *= 0.7;
+			
+			// Opaque backing to force the scroll elements
+			// to match other components by default.
+			drawRoundRect(
+				1, 0, w - 3, h, cr,
+				backgroundColor, 0.2);                            
+	
+			switch (name)
+			{
+				default:
+				case "thumbUpSkin":
+				{
+					fillColors[0] = ColorUtil.adjustBrightness(fillColors[0], 100.0);
+	   				var upFillColors:Array = [ fillColors[0], fillColors[1] ];
+	   				
+					var upFillAlphas:Array = [ fillAlphas[0], fillAlphas[1] ];
+	
+					// positioning placeholder
+					drawRoundRect(
+						0, 0, w, h, 0,
+						0xFFFFFF, 0); 
+	
+					// shadow
+					if (horizontal)
+					{
+						drawRoundRect(
+							1, 0, w - 2, h, cornerRadius,
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [ 1, 0 ],
+							horizontalGradientMatrix(2, 0, w, h),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: 1, w: w - 4, h: h - 2, r: cr1 });
+					}
+					else
+					{
+						drawRoundRect(
+							1, h - radius, w - 3, radius + 4,
+							{ tl: 0, tr: 0, bl: 0, br: radius },
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [ 1, 0 ],
+							horizontal ?
+							horizontalGradientMatrix(0, h - 4, w - 3, 8) :
+							verticalGradientMatrix(0, h - 4, w - 3, 8),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: h-radius, w: w - 4, h: radius,
+							  r: { tl: 0, tr: 0, bl: 0, br: radius - 1 } }); 
+					}
+					// border
+					drawRoundRect(
+						1, 0, w - 3, h, cr,
+						[ borderColor, derStyles.borderColorDrk1 ], 1,
+						horizontal ?
+						horizontalGradientMatrix(0, 0, w, h) :
+						verticalGradientMatrix(0, 0, w, h),
+						GradientType.LINEAR, null, 
+						{ x: 1, y: 1, w: w - 4, h: h - 2, r: cr1 });  
+	
+					// fill
+					drawRoundRect(
+						1, 1, w - 4, h - 2, cr1,
+						upFillColors, upFillAlphas,
+						horizontal ?
+						horizontalGradientMatrix(1, 0, w - 2, h - 2) :
+						verticalGradientMatrix(1, 0, w - 2, h - 2)); 
+	
+					// highlight
+					if (horizontal)
+					{
+						drawRoundRect(
+							1, 0, (w - 4) / 2, h - 2, 0,
+							[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
+							horizontalGradientMatrix(1, 1, w - 4, (h - 2) / 2)); 
+					}
+					else
+					{
+						drawRoundRect(
+							1, 1, w - 4, (h - 2) / 2, cr1,
+							[ 0xFFFFFF, 0xFFFFFF ], highlightAlphas,
+							horizontal ?
+							horizontalGradientMatrix(1, 0, (w - 4) / 2, h - 2) :
+							verticalGradientMatrix(1, 1, w - 4, (h - 2) / 2)); 
+					}
+					break;
+				}
+				
+				case "thumbOverSkin":
+				{
+					var overFillColors:Array;
+					if (fillColors.length > 2)
+						overFillColors = [ fillColors[2], fillColors[3] ];
+					else
+						overFillColors = [ fillColors[0], fillColors[1] ];
+	
+					var overFillAlphas:Array;
+					if (fillAlphas.length > 2)
+						overFillAlphas = [ fillAlphas[2], fillAlphas[3] ];
+	  				else
+						overFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
+	
+					// positioning placeholder
+					drawRoundRect(
+						0, 0, w, h, 0,
+						0xFFFFFF, 0); 
+	
+					// shadow
+					if (horizontal)
+					{
+						drawRoundRect(
+							1, 0, w - 2, h, cornerRadius,
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [ 1, 0 ],
+							horizontalGradientMatrix(2, 0, w, h),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: 1, w: w - 4, h: h - 2, r: cr1 });
+					}
+					else
+					{
+						drawRoundRect(
+							1, h - radius, w - 3, radius + 4,
+							{ tl: 0, tr: 0, bl: 0, br: radius },
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [ 1, 0 ],
+							horizontal ?
+							horizontalGradientMatrix(0, h - 4, w - 3, 8) :
+							verticalGradientMatrix(0, h - 4, w - 3, 8),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: h-radius, w: w - 4, h: radius,
+							  r: { tl: 0, tr: 0, bl: 0, br: radius - 1 } }); 
+					}
+									
+					// border
+					drawRoundRect(
+						1, 0, w - 3, h, cr,
+						[ themeColor, derStyles.themeColDrk1], 1,
+						horizontal ?
+						horizontalGradientMatrix(1, 0, w, h) :
+						verticalGradientMatrix(0, 0, w, h),
+						GradientType.LINEAR, null, 
+	                    { x: 1, y: 1, w: w - 4, h: h - 2, r: cr1 });
+	
+					// fill
+					drawRoundRect(
+						1, 1, w - 3, h - 2, cr1,
+						//1, 1, w - 2, h - 2, cr1,
+						//1, 1, w - 4, h - 2, cr1,
+						overFillColors, overFillAlphas,
+						horizontal ?
+						horizontalGradientMatrix(1, 0, w, h) :
+						verticalGradientMatrix(1, 0, w, h)); 
+					
+					break;
+				}
+				
+				case "thumbDownSkin":
+				{				
+					// shadow
+					if (horizontal)
+					{
+						drawRoundRect(
+							1, 0, w - 2, h, cr,
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [1, 0],
+							horizontalGradientMatrix(2, 0, w, h),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: 1, w: w - 4, h: h - 2, r: cr1 }); 
+					}
+					else
+					{
+						drawRoundRect(
+							1, h - radius, w - 3, radius + 4,
+							{ tl: 0, tr: 0, bl: 0, br: radius },
+							[ derStyles.borderColorDrk1,
+							  derStyles.borderColorDrk1 ], [ 1, 0 ],
+							horizontal ?
+							horizontalGradientMatrix(0, h - 4, w - 3, 8) :
+							verticalGradientMatrix(0, h - 4, w - 3, 8),
+							GradientType.LINEAR, null, 
+							{ x: 1, y: h-radius, w: w - 4, h: radius,
+							  r: { tl: 0, tr: 0, bl: 0, br: radius - 1 } }); 
+					}
+	
+					// border
+					drawRoundRect(
+						1, 0, w - 3, h, cr,
+						[ themeColor, derStyles.themeColDrk2], 1,
+						horizontal ?
+						horizontalGradientMatrix(1, 0, w, h) :
+						verticalGradientMatrix(0, 0, w, h),
+						GradientType.LINEAR, null, 
+	                    { x: 1, y: 1, w: w - 4, h: h - 2, r: cr1});  
+	
+					// fill
+					drawRoundRect(
+						//0.5, 1, w - 1, h - 2, cr1,
+						0.5, 1, w - 3, h - 2, cr1,
+						//1, 1, w - 4, h - 2, cr1,
+						[ derStyles.fillColorPress1, derStyles.fillColorPress2 ], 1,
+						horizontal ?
+						horizontalGradientMatrix(1, 0, w, h) :
+						verticalGradientMatrix(1, 0, w, h)); 
+										
+					break;
+				}
+				
+				case "thumbDisabledSkin":
+				{
+					// positioning placeholder
+					drawRoundRect(
+						0, 0, w, h, 0,
+						0xFFFFFF, 0); 
+					
+					// border
+					drawRoundRect(
+						1, 0, w - 3, h, cr,
+						0x999999, 0.5);
+					
+					// fill
+					drawRoundRect(
+						1, 1, w - 4, h - 2, cr1,
+						0xFFFFFF, 0.5);
+					
+					break;
+				}
+			}
+			
+			// Draw grip.
+			
+			//var gripW:Number = Math.floor(w / 2 - 4);
+			var gripW:Number = Math.floor(w / 2 - 3);
+			
+			var gripThick:Number = 5;
+			
+			drawRoundRect(
+				gripW, Math.floor(h / 2 - 4), gripThick, 1, 0,
+				0x000000, 0.4);
+			
+			drawRoundRect(
+				gripW, Math.floor(h / 2 - 2), gripThick, 1, 0,
+				0x000000, 0.4);
+			
+			drawRoundRect(
+				gripW, Math.floor(h / 2), gripThick, 1, 0,
+				0x000000, 0.4);
+			
+			drawRoundRect(
+				gripW, Math.floor(h / 2 + 2), gripThick, 1, 0,
+				0x000000, 0.4);
+	
+			drawRoundRect(
+				gripW, Math.floor(h / 2 + 4), gripThick, 1, 0,
+				0x000000, 0.4);
+		}
+	
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/ScrollableAxisRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/ScrollableAxisRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/ScrollableAxisRenderer.as	(revision 15)
@@ -0,0 +1,310 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Author: Joel May
+//  connectedpixel.com
+//  All code here not owned by Adobe Systems Incorporated is in the public domain.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//	Modified by Tomasz Hulak
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package gssim.gssimstudio.editor.charts.com.connectedpixel.charts
+{
+	import flash.geom.Rectangle;
+	
+	import mx.charts.AxisRenderer;
+	import mx.charts.chartClasses.CartesianChart;
+	import mx.controls.scrollClasses.ScrollBarDirection;
+	import mx.graphics.IStroke;
+
+	[Style(name="scrollBarThemeColor", type="uint", format="Color", inherit="yes")]
+	
+	[Style(name="scrollBarDownArrowDownSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarDownArrowOverSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarThumbIcon", type="Class", inherit="no")]
+	[Style(name="scrollBarThumbDownSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarThumbOverSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarThumbUpSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarTrackColors", type="Array", arrayType="uint", format="Color", inherit="no")]
+	[Style(name="scrollBarTrackSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarUpArrowDisabledSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarUpArrowDownSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarUpArrowOverSkin", type="Class", inherit="no")]
+	[Style(name="scrollBarUpArrowUpSkin", type="Class", inherit="no")]
+
+	public class ScrollableAxisRenderer extends AxisRenderer
+	{
+		// These styles will be passed to the contained scrollbar when this initializes.
+		static private var styleArray:Array = [
+			"scrollBarThumbDownSkin", 			
+			"scrollBarThumbOverSkin", 			
+			"scrollBarThumbUpSkin", 			
+			"scrollBarThumbDownSkin", 			
+			"scrollBarDownArrowDisabledSkin", 	
+			"scrollBarDownArrowDownSkin", 		
+			"scrollBarDownArrowOverSkin", 		
+			"scrollBarDownArrowUpSkin", 		
+			"scrollBarUpArrowDisabledSkin",		
+			"scrollBarUpArrowDownSkin", 		
+			"scrollBarUpArrowOverSkin", 		
+			"scrollBarUpArrowUpSkin", 			
+			"scrollBarTrackSkin" 				
+		];
+		
+		/////////////////////////////////////////////////////////////////////////////	
+		
+		private var _scrollBar:ChartDataScrollBar;
+		
+		public function get chartScroller() : ChartDataScrollBar
+		{
+			return _scrollBar;
+		}
+		
+		private var nColumns:int = 5;	
+		private var bnColumnsChanged:Boolean = false;
+		
+		private var _alteredStyles:Object = new Object();
+		
+		public function ScrollableAxisRenderer()
+		{
+			super();
+			initAlteredStyles();
+		}
+		
+		private function initAlteredStyles():void
+		{
+  			for (var i:int = 0 ; i < styleArray.length ; i++){
+				var styleName:String = styleArray[i];
+				_alteredStyles[styleName] = true;
+			}
+		}
+		
+		override public function styleChanged(styleProp:String):void
+		{
+			super.styleChanged(styleProp);
+			
+			// If it starts with 'scrollBar', it is a style for the scroll
+			// bar.  Log the change here and forward it in updateDisplayList().
+			var prefix:String = "scrollBar";
+			if (styleProp != null && styleProp.indexOf(prefix) == 0){
+				_alteredStyles[styleProp] = true;
+				invalidateDisplayList();
+			}
+			
+		}
+		
+		/////////////////////////////////////////////
+		[Bindable]
+		public function set maxVisibleColumns(n:int):void
+		{
+			if (this.nColumns != n)
+			{
+				this.nColumns = n;	
+				this.bnColumnsChanged = true;
+				this.invalidateProperties();
+			}
+		}
+		public function get maxVisibleColumns():int
+		{
+			return this.nColumns;
+		}
+		
+		[Bindable]
+		public function set firstIndexOffset(iCol:int):void
+		{
+			_scrollBar.firstIndexOffset = iCol;
+		}
+		public function get firstIndexOffset():int
+		{
+			return _scrollBar.firstIndexOffset;
+		}
+		
+		/////////////////////////////////////////////
+		
+		override protected function createChildren():void
+		{
+			/*
+			if (this.chart is BarChart){
+				if (horizontal){
+					throw new Error("ScrollableAxisRenderer can only render the vertical axis on a BarChart");
+				}
+			}
+			else if (this.chart is ColumnChart){
+				if (!horizontal){
+					throw new Error("ScrollableAxisRenderer can only render the horizontal axis on a ColumnChart");
+				}
+			}
+			else{
+				throw new Error("ScrollableAxisRenderer only works with ColumnCharts and BarCharts");
+			}
+			*/
+			//super.createChildren();
+			
+			if (_scrollBar == null){
+				var dir:String = horizontal ? ScrollBarDirection.HORIZONTAL : ScrollBarDirection.VERTICAL;
+				_scrollBar = new ChartDataScrollBar(dir);
+				
+				// compensate for crazy rotation of a vertical axis renderer.
+				_scrollBar.rotation = -this.rotation;	 
+				_scrollBar.visible = true;
+				addChild(_scrollBar);
+				
+				_scrollBar.chart = this.chart as CartesianChart;
+			}
+		}
+		override protected function commitProperties():void
+		{
+			super.commitProperties();
+			
+			if (bnColumnsChanged){
+				bnColumnsChanged = false;
+				_scrollBar.maxColumns = nColumns;
+			}
+		}
+
+		override protected function updateDisplayList(unscaledWidth:Number,
+													  unscaledHeight:Number):void
+		{
+			super.updateDisplayList(unscaledWidth, unscaledHeight);
+	
+			drawScrollBar();
+			
+			updateScrollBarStyles();
+		}
+		
+		private function updateScrollBarStyles():void
+		{
+			for (var styleProp:String in _alteredStyles){
+				var prefix:String = "scrollBar";
+				if (styleProp.indexOf(prefix) == 0){
+					// Fix the name.  e.g. Change from scrollBarUpArrowSkin to upArrowSkin.
+					var scrollStyleProp:String = styleProp.substr(prefix.length);
+					// Fix the first letter capitalization.
+					scrollStyleProp = scrollStyleProp.charAt(0).toLowerCase() + scrollStyleProp.substr(1);
+					
+					var propVal:* = this.getStyle(styleProp);		
+					if (propVal != undefined){
+						_scrollBar.setStyle(scrollStyleProp, propVal);		
+					}
+				}
+			}
+			_alteredStyles = new Object();
+		}
+		
+		private var _bScrollBarNeedsDrawing:Boolean = true;
+		private var _scrollX:Number;
+		private var _scrollY:Number;
+		private var _scrollW:Number;
+		private var _scrollH:Number;
+		private var _scrollInitialized : Boolean = false;
+		
+		public function set scrollInitialized(value : Boolean) : void
+		{
+			_scrollInitialized = value;
+		}
+		
+		public function set scrollWidth(value : Number) : void
+		{
+			_scrollW = value;
+		}
+		public function get scrollWidth() : Number
+		{
+			return _scrollW;
+		}
+		
+		public function estimateScollBarSize() : void
+		{
+			_scrollInitialized = false;
+			//drawScrollBar();
+			
+			var barRect:Rectangle = horizontal ? calcHorzScrollBarRect() : calcVertScrollBarRect();
+			var scX:Number = barRect.left;
+			var scY:Number = barRect.top;
+			var scW:Number = barRect.width;
+			trace(scW.toString());
+			var scH:Number = barRect.height;
+			_scrollX = scX;
+			_scrollY = scY;
+			_scrollW = scW;
+			_scrollH = scH;
+			_scrollBar.move(_scrollX, _scrollY);
+			_scrollBar.setActualSize(_scrollW, _scrollH);
+		}
+		
+		private function drawScrollBar():void
+		{
+			var barRect:Rectangle = horizontal ? calcHorzScrollBarRect() : calcVertScrollBarRect();
+			
+			var scX:Number = barRect.left;
+			var scY:Number = barRect.top;
+			var scW:Number = barRect.width;
+			var scH:Number = barRect.height;
+			
+			if (scX == _scrollX && scY == _scrollY && scW == _scrollW && scH == _scrollH){
+				// Don't mess with the scroll bar unless necessary.
+				// This function is called in response to moving the scroll bar.
+				// Therefore, we would be redrawing the scrollbar like crazy unless
+				// we prevent that here.
+				return;
+			}
+			
+			if (!_scrollInitialized)
+			{
+				_scrollX = scX;
+				_scrollY = scY;
+				_scrollW = scW;
+				_scrollH = scH;
+				_scrollInitialized = true;
+			}
+
+			_scrollBar.move(_scrollX, _scrollY);
+			_scrollBar.setActualSize(_scrollW, _scrollH);
+		}
+		
+		// Figure out the rectangle that corresponds to the drawn axis.  
+		// The scrollbar will overlay the axis.  
+		
+		private function calcHorzScrollBarRect():Rectangle
+		{
+			var axisStroke:IStroke = getStyle("axisStroke");
+			
+			var w:Number = Number(axisStroke.weight == 0 ? 1 : axisStroke.weight);
+									  
+			var bInverted:Boolean = this.placement == "top";
+			
+			// Prevent repeated function calls.
+			var guts:Rectangle = gutters;
+	
+			var rectL:Number = guts.left;
+			var rectT:Number = bInverted ? guts.top - w : unscaledHeight - guts.bottom ;
+			rectT += w/2;
+			var rectW:Number = unscaledWidth -guts.right - rectL;
+			var rectH:Number = w;
+			var r:Rectangle = new Rectangle(rectL, rectT, rectW, rectH);
+			return r;
+		}
+		
+		private function calcVertScrollBarRect():Rectangle
+		{
+			var axisStroke:IStroke = getStyle("axisStroke");
+			
+			var w:Number = Number(axisStroke.weight == 0 ? 1 : axisStroke.weight);
+				
+			var bInverted:Boolean = this.placement == "right";
+			
+			var guts:Rectangle = gutters;
+	
+			var rectL:Number = guts.top; 
+			var rectT:Number = bInverted ? guts.right-w : unscaledHeight-guts.left;
+			rectT += w/2;
+			var rectW:Number = w;
+			var rectH:Number = unscaledWidth-guts.bottom-guts.top;
+			
+			var r:Rectangle = new Rectangle(rectL,rectT,rectW,rectH);
+			return r;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/ChartDataScrollBar.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/ChartDataScrollBar.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/charts/com/connectedpixel/charts/ChartDataScrollBar.as	(revision 15)
@@ -0,0 +1,487 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Author: Joel May
+//  connectedpixel.com
+//  All code here not owned by Adobe Systems Incorporated is in the public domain.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//	Modified by Tomasz Hulak
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package gssim.gssimstudio.editor.charts.com.connectedpixel.charts
+{
+	import gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollThumbSkin;
+	import gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollTrackSkin;
+	import gssim.gssimstudio.editor.charts.com.connectedpixel.collections.SubRangeArrayCollection;
+	
+	import flash.events.Event;
+	
+	import mx.charts.DateTimeAxis;
+	import mx.charts.LinearAxis;
+	import mx.charts.chartClasses.CartesianChart;
+	import mx.charts.chartClasses.IAxis;
+	import mx.collections.IList;
+	import mx.controls.HScrollBar;
+	import mx.controls.VScrollBar;
+	import mx.controls.scrollClasses.ScrollBar;
+	import mx.controls.scrollClasses.ScrollBarDirection;
+	import mx.core.UIComponent;
+	import mx.styles.CSSStyleDeclaration;
+	import mx.styles.StyleManager;
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollArrowSkin
+ */
+	[Style(name="downArrowDownSkin", type="Class", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollArrowSkin
+ */
+	[Style(name="downArrowOverSkin", type="Class", inherit="no")]
+	[Style(name="thumbIcon", type="Class", inherit="no")]
+	
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollThumbSkin
+ */
+ 
+	[Style(name="thumbDownSkin", type="Class", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollThumbSkin
+ */	
+ 	[Style(name="thumbDownSkin", type="Class", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollThumbSkin
+ */	
+	[Style(name="thumbOverSkin", type="Class", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollThumbSkin
+ */	
+	[Style(name="thumbUpSkin", type="Class", inherit="no")]
+	
+	[Style(name="trackColors", type="Array", arrayType="uint", format="Color", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollTrackSkin
+ */	
+	[Style(name="trackSkin", type="Class", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollArrowSkin
+ */	
+	[Style(name="upArrowDisabledSkin", type="Class", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @defaultcom.connectedpixel.charts.skins.AxisScrollArrowSkin 
+ */	
+	[Style(name="upArrowDownSkin", type="Class", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollArrowSkin
+ */	
+	[Style(name="upArrowOverSkin", type="Class", inherit="no")]
+/**
+ *  Name of the class to use as the skin for the down arrow button of the 
+ *  scroll bar when it is disabled. 
+ * 
+ *  If you change the skin, either graphically or programmatically, 
+ *  you should ensure that the new skin is the same height 
+ *  (for horizontal ScrollBars) or width (for vertical ScrollBars) as the track.
+ * 
+ *  @default com.connectedpixel.charts.skins.AxisScrollArrowSkin
+ */	
+	[Style(name="upArrowUpSkin", type="Class", inherit="no")]
+	
+	// It would have been easier to extend ScrollBar instead of wrapping ScrollBar.  This would have
+	// simplified all this skin style forwarding.  However, ScrollBar has some mx_internal data members
+	// which need to be set (see HScrollBar for exampl).  This mucks it up, so wrapping wins over inheriting.
+	
+	public class ChartDataScrollBar extends UIComponent
+	{
+		// These skins are derived from the Halo scrollbar skins.  They have a nasty hack.  Because the flex
+		// ScrollBar class hard-codes the minimum width and we desire a narrow width here, these appear to be
+		// narrower, but have an alpha=0 background rectangle that is the same width as the normal ScrollBar.
+		
+		static private var defaultStyles:Array = [
+			{ name: "thumbDownSkin", 			styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollThumbSkin },
+			{ name: "thumbOverSkin", 			styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollThumbSkin },
+			{ name: "thumbUpSkin", 				styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollThumbSkin },
+			{ name: "thumbDownSkin", 			styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollThumbSkin },
+			
+			{ name: "downArrowDisabledSkin", 	styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollArrowSkin },
+			{ name: "downArrowDownSkin", 		styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollArrowSkin },
+			{ name: "downArrowOverSkin", 		styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollArrowSkin },
+			{ name: "downArrowUpSkin", 			styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollArrowSkin },
+			
+			{ name: "upArrowDisabledSkin", 		styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollArrowSkin },
+			{ name: "upArrowDownSkin", 			styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollArrowSkin },
+			{ name: "upArrowOverSkin", 			styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollArrowSkin },
+			{ name: "upArrowUpSkin", 			styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollArrowSkin },
+			
+			{ name: "trackSkin", 				styleValue: gssim.gssimstudio.editor.charts.com.connectedpixel.charts.skins.AxisScrollTrackSkin }
+		];
+		
+		// Code structure from "Programming Flex 2" by Chafic Kazoun and Joey Lott.
+		
+		private static var classConstructed:Boolean = classConstruct();
+		
+		private static function classConstruct():Boolean {
+	       var style:CSSStyleDeclaration = StyleManager.getStyleDeclaration("ChartDataScrollBar");
+    
+        	if (!style)
+        	{
+            	style = new CSSStyleDeclaration();
+				StyleManager.setStyleDeclaration("ChartDataScrollBar", style, true);
+        	}
+  			for (var i:int = 0 ; i < defaultStyles.length ; i++){
+				var styleItem:Object = defaultStyles[i];
+				var styleName:String = styleItem.name;
+				var styleValue:* = styleItem.styleValue;
+				if (style.getStyle(styleName) == undefined){
+					style.setStyle(styleName, styleValue);
+				}
+			}
+       	
+			return true;		
+		}
+		
+		/////////////////////////////////////////////////////////////////
+		
+		private var nColumns:int = 5;	
+		private var bnColumnsChanged:Boolean = false;
+			
+		private var iStartColumn:int = 0;
+		private var biStartColumnChanged:Boolean = false;
+			
+		private var innerDP:IList;
+		private var rangeWrapper:SubRangeArrayCollection;
+		
+		private var _alteredStyles:Object = new Object();
+			
+		private var _scrollBar:ScrollBar;
+		
+		public function get scrollBar() : ScrollBar
+		{
+			return _scrollBar;
+		}
+		
+		private var _bMaxColumnsChanged:Boolean = false;
+		private var _nMaxColumns:int = 5;
+		
+		private var _bInitialLeftColumnChanged:Boolean = false;
+		private var _iInitialLeftColumn:int = 0;
+		
+		private var _chart:CartesianChart;
+		
+		// ScrollBarDirection.HORIZONTAL
+		// ScrollBarDirection.VERTICAL	
+		private var _direction:String;
+		
+		public function get direction():String { return _direction; }
+		
+		public function ChartDataScrollBar(scrollBarDirection:String)
+		{
+			super();
+			if (scrollBarDirection != ScrollBarDirection.HORIZONTAL && 
+			    scrollBarDirection != ScrollBarDirection.VERTICAL      ){
+			    var msg:String = "ChartDataScrollBar: Invalid scrollBarDirection: " + scrollBarDirection;
+				throw new ArgumentError(msg);
+			}
+			_direction = scrollBarDirection;
+			
+			initAlteredStyles();
+		}
+		
+		private function initAlteredStyles():void
+		{
+			for (var i:int = 0 ; i < defaultStyles.length ; i++){
+				var styleName:String = defaultStyles[i].name;
+				_alteredStyles[styleName] = true;
+			}
+		}
+		
+		
+		override public function styleChanged(styleProp:String):void
+		{
+			super.styleChanged(styleProp);
+			
+			_alteredStyles[styleProp] = true;
+			
+			invalidateDisplayList();
+		}
+		
+		override public function setActualSize(w:Number, h:Number):void
+		{
+			super.setActualSize(w,h);
+			
+			if (_scrollBar != null){
+				_scrollBar.setActualSize(w,h);
+			}
+		}
+		
+		override protected function createChildren():void
+		{
+			if (_scrollBar == null){
+				_scrollBar = (_direction == ScrollBarDirection.HORIZONTAL) ? new HScrollBar() : new VScrollBar();
+	            _scrollBar.styleName = this;
+				_scrollBar.addEventListener(Event.SCROLL,onScroll);
+
+				addChild(_scrollBar);
+			}
+		}
+		
+		[Bindable]
+		public function set chart(ch:CartesianChart):void
+		{
+			if (ch == _chart) return;
+			
+			_chart = ch;	
+			
+			// Prevent the chart from flashing the full data set 
+			// during initialization -- hide it.  This will be restored in
+			// updateDisplayList()
+			_chart.alpha = 0;
+			
+			_bChartSynched = false;
+			this.invalidateDisplayList();
+			this.invalidateProperties();
+			this.invalidateSize();
+		}
+		public function get chart():CartesianChart { return _chart; }
+		
+		private var _bChartSynched:Boolean = false;
+		
+		private function chartSynch():void
+		{
+			if (_chart == null) return;
+			if (_chart.dataProvider == null)
+			{ 
+				this.invalidateProperties();
+				return; 
+			}
+			
+			if (_bChartSynched) return;	
+			
+			_bChartSynched = true;
+			
+			var axis:IAxis = (direction == ScrollBarDirection.HORIZONTAL) ? _chart.verticalAxis : _chart.horizontalAxis;
+			
+			if (axis is LinearAxis)
+			{
+				var linAxis:LinearAxis = axis as LinearAxis;
+				if (isNaN(linAxis.minimum) || isNaN(linAxis.maximum))
+				{
+					this.invalidateProperties();
+					return;
+				} 
+				// Hack: Max and min are now explicitly set, so altering the 
+				// chart data provider won't change them.
+				linAxis.minimum = linAxis.minimum;
+				linAxis.maximum = linAxis.maximum;
+			}
+			else if (axis is DateTimeAxis)
+			{
+				var dateAxis : DateTimeAxis = axis as DateTimeAxis;
+				if (isNaN(dateAxis.minimum.getTime()) || isNaN(dateAxis.maximum.getTime()))
+				{
+					this.invalidateProperties();
+					return;
+				} 
+				// Hack: Max and min are now explicitly set, so altering the 
+				// chart data provider won't change them.
+				dateAxis.minimum = dateAxis.minimum;
+				dateAxis.maximum = dateAxis.maximum;
+			} 
+			
+			innerDP = _chart.dataProvider as IList;
+			
+			if (innerDP != null)
+			{
+				rangeWrapper = new SubRangeArrayCollection(innerDP,nColumns,iStartColumn);
+				_chart.dataProvider = rangeWrapper; 
+			}
+		}
+		
+		[Bindable]
+		public function set maxColumns(n:int):void
+		{
+			if (innerDP != null && n > innerDP.length){
+				n = innerDP.length;
+			}
+			
+			if (nColumns != n){
+				
+				if (innerDP != null){
+					var nColumnsExcessRight:int = iStartColumn + n - innerDP.length;
+					if (nColumnsExcessRight > 0){
+						firstIndexOffset = iStartColumn - nColumnsExcessRight;
+					}
+				}
+				
+				nColumns = n;	
+				bnColumnsChanged = true;
+				
+				invalidateDisplayList();
+			}
+		}
+		public function get maxColumns():int
+		{
+			return this.nColumns;
+		}
+		
+		[Bindable]
+		public function set firstIndexOffset(iCol:int):void
+		{
+			if (this.iStartColumn != iCol){
+				iStartColumn = iCol;
+				this.bnColumnsChanged = true;
+				this.invalidateProperties();
+			}
+		}
+		public function get firstIndexOffset():int
+		{
+			return iStartColumn;
+		}
+		
+		private function updateScrollBar():void
+		{
+			_scrollBar.minScrollPosition = 0;
+			_scrollBar.maxScrollPosition = 	innerDP.length - this.nColumns;		
+			_scrollBar.pageSize = nColumns;
+			
+			if (this.direction == ScrollBarDirection.VERTICAL){
+				_scrollBar.scrollPosition = innerDP.length - iStartColumn - this.nColumns;
+			}
+			else{
+				_scrollBar.scrollPosition = iStartColumn;
+			}
+
+			_scrollBar.addEventListener(Event.SCROLL, onScroll);
+		}
+		
+		///////////////////////////////////////////////
+		
+		override protected function measure():void
+		{
+			super.measure();
+			
+			// Bubble up the values from the wrapped scrollbar.
+			measuredWidth  = this._scrollBar.measuredWidth;
+			measuredHeight = this._scrollBar.measuredHeight;
+			measuredMinWidth  = this._scrollBar.measuredMinWidth;
+			measuredMinHeight = this._scrollBar.measuredMinHeight;
+		}
+		
+		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.updateDisplayList(unscaledWidth, unscaledHeight);	
+			
+			_scrollBar.setActualSize(unscaledWidth, unscaledHeight);
+			
+			chartSynch();
+			
+			if (this.bnColumnsChanged){
+				rangeWrapper.setRange(firstIndexOffset, nColumns);
+				this.bnColumnsChanged = false;
+			}
+			
+			updateScrollBar();
+			
+			updateScrollBarStyles();
+			
+			// Restore the chart to visibility now that it has the correct data and
+			// any temporary flash of bad data will not happen now.
+			_chart.alpha = 1.0;
+		}
+		
+		private function updateScrollBarStyles():void
+		{
+			for (var styleProp:String in _alteredStyles){
+				_scrollBar.setStyle(styleProp, this.getStyle(styleProp));
+			}
+			_alteredStyles = new Object();
+		}
+
+		private function onScroll(ev:Event):void
+		{
+			var scrollBar:ScrollBar = ScrollBar(ev.target);
+			
+			if (this.direction == ScrollBarDirection.VERTICAL){
+				iStartColumn = innerDP.length - scrollBar.scrollPosition - this.nColumns; 
+			}
+			else{
+				iStartColumn = scrollBar.scrollPosition;
+			}
+			
+			if (rangeWrapper != null){
+				rangeWrapper.firstIndexOffset = iStartColumn;
+			}
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ResourceViewerTest.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ResourceViewerTest.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ResourceViewerTest.mxml	(revision 15)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:v="charts.*" layout="absolute">
+	<mx:Panel title="ResourceViewer Test" height="400" width="900">
+		<v:ResourceViewer id="resourceViewer" width="100%" height="100%" />
+	</mx:Panel>
+</mx:Application>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudio.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudio.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudio.mxml	(revision 15)
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vine:VineApplication
+				xmlns="gssim.gssimstudio.editor.*"
+				xmlns:views="gssim.gssimstudio.editor.views.*"
+				xmlns:components="gssim.gssimstudio.editor.gssim.components.*"
+				xmlns:fx="http://ns.adobe.com/mxml/2009"  
+				xmlns:s="library://ns.adobe.com/flex/spark"
+				xmlns:mx="library://ns.adobe.com/flex/mx"
+				xmlns:vine="org.vinetoolkit.vine.*"
+				creationComplete="initApp();"
+				backgroundColor="#EBE9E1"
+				preloader="gssim.gssimstudio.editor.script.preloader.CustomPreloader"
+				paddingLeft="0" paddingRight="0"
+				paddingTop="0" paddingBottom="0">
+	
+<fx:Metadata>
+[ResourceBundle("Common")]
+[ResourceBundle("Help")]
+</fx:Metadata>
+
+<fx:Declarations>
+<GSSimStudioModel id="gsSimStudioModel"/>
+	
+<fx:XML id="xml">
+<grmsJob appId="gssim">
+	<task persistent="true" taskId="gssim">
+		<execution type="single">
+			<executable>
+				<application name="GSSIM" version="jszymczak"/>
+			</executable>
+			<arguments>
+				<value>input/experiment.properties</value>
+			</arguments>                                                                                        
+			<stageInOut>
+				<directory name="input" type="in">
+					<location type="URL">gsiftp://grass1.man.poznan.pl//home/mcichenski/gssim/input</location>
+				</directory>
+				
+				<directory name="output" type="out">
+					<location type="URL">gsiftp://grass1.man.poznan.pl//home/mcichenski/gssim/output/$\{JOB_ID}-$\{TASK_ID}</location>
+				</directory>
+
+				<file name="gssim.log" type="out" required="false">
+					<location type="URL">gsiftp://grass1.man.poznan.pl//home/mcichenski/gssim/output/$\{JOB_ID}-$\{TASK_ID}/gssim.log</location>
+				</file>
+
+				<file name="trash.log" type="out" required="false">
+					<location type="URL">gsiftp://grass1.man.poznan.pl//home/mcichenski/gssim/output/$\{JOB_ID}-$\{TASK_ID}/trash.log</location>
+				</file>
+			</stageInOut>
+		</execution>
+	</task>
+</grmsJob>
+</fx:XML>
+</fx:Declarations>
+
+	<fx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.skins.IconButtonSkin;
+			
+			public var isFileTransfering : Boolean = false;
+			
+			/**
+			 * Sets the current selected language button to the initialized locale.
+			 */
+			private function initApp() : void
+			{
+				//setDebugMode(true);
+				if (resourceManager.localeChain[0] == "pl_PL") languageMenu.selected = plLocale;
+				else if (resourceManager.localeChain[0] == "en_US") languageMenu.selected = enLocale;
+				else languageMenu.selected = enLocale; //default
+				
+				bindModel("gsSimStudioModel");
+				
+				addModelUpdatedResultCallback(archiveViewer.convertToXml);
+			}
+				
+			/**
+			 * This function moves the picked locale to the top of locale chain list.
+			 */
+			private function changeLocale(locale : String) : void
+			{
+				var loc : Array = new Array;
+				loc.push(locale);
+				for each (var item : String in resourceManager.localeChain)
+				{
+					if (item != locale) loc.push(item);
+				}
+				resourceManager.localeChain = loc;
+				//refresh editors
+				if (workloadEditor != null && workloadEditor.ErrorList != null) workloadEditor.ErrorList.invalidateList();
+			} 			
+		]]>
+	</fx:Script>
+<s:SkinnableContainer width="100%" height="100%">
+	
+	<mx:ViewStack id="viewStack" selectedIndex="0" width="100%" height="100%" creationPolicy="all" backgroundColor="{backgroundColorPicker.selectedColor}">
+		<views:ExperimentEditor id="experimentEditor" objectCanvas="{topologyEditor.objectCanvas}"/>
+		<views:TopologyEditor id="topologyEditor"/>
+		<views:WorkloadEditor id="workloadEditor"/>
+		<views:ArchiveViewer id="archiveViewer"/>
+	</mx:ViewStack>
+	
+	<mx:ColorPicker selectedColor="0xEBE9E1" id="backgroundColorPicker" y="288"/>
+	
+	<components:RollOutMenu width="100%" height="100%" selectable="true" y="256" id="languageMenu">
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="changeLocale('en_US')" id="enLocale" height="32" width="32" toolTip="{resourceManager.getString('Common', 'English')}" iconUp="assets/icon/en_US.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="changeLocale('pl_PL')" id="plLocale" height="32" width="32" toolTip="{resourceManager.getString('Common', 'Polish')}" iconUp="assets/icon/pl_PL.png"/>
+	</components:RollOutMenu>
+	
+	<!--<components:RollOutMenu width="100%" height="100%" selectable="true" >-->
+	<mx:VBox verticalGap="0">
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="viewStack.selectedChild=experimentEditor;"
+			height="64" width="64" toolTip="{resourceManager.getString('Common', 'ExperimentEditor')}"
+			iconUp="assets/menu/ExperimentEditor.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="viewStack.selectedChild=topologyEditor;"
+			height="64" width="64" toolTip="{resourceManager.getString('Common', 'TopologyEditor')}"
+			iconUp="assets/menu/NetworkEditor.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="viewStack.selectedChild=workloadEditor;"
+			height="64" width="64" toolTip="{resourceManager.getString('Common', 'WorkloadGeneratorEditor')}"
+			iconUp="assets/menu/WorkloadEditor.png"/>
+		<components:IconToggleButton skinClass="gssim.gssimstudio.editor.gssim.skins.IconToggleButtonSkin" click="viewStack.selectedChild=archiveViewer;"
+		    height="64" width="64" toolTip="{resourceManager.getString('Common', 'ArchiveViewer')}"
+		    iconUp="assets/menu/ArchiveEditor.png"/>
+	</mx:VBox>
+	<!--</components:RollOutMenu>-->
+</s:SkinnableContainer>
+	
+</vine:VineApplication>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/LineSprite.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/LineSprite.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/LineSprite.as	(revision 15)
@@ -0,0 +1,50 @@
+package gssim.gssimstudio.editor.flare.display
+{
+	/**
+	 * A Sprite representing a line. Supports position, color, and width
+	 * properties.
+	 */
+	public class LineSprite extends DirtySprite
+	{
+		private var _color:uint = 0xcccccc;
+		private var _width:Number = 0;
+		private var _x1:Number;
+		private var _y1:Number;
+		private var _x2:Number;
+		private var _y2:Number;
+		
+		/** The x-coordinate for the first line endpoint. */
+		public function get x1():Number  { return _x1; }
+		public function set x1(x:Number):void { _x1 = x; dirty(); }
+		
+		/** The y-coordinate for the first line endpoint. */
+		public function get y1():Number  { return _y1; }
+		public function set y1(y:Number):void { _y1 = y; dirty(); }
+		
+		/** The x-coordinate for the second line endpoint. */
+		public function get x2():Number  { return _x2; }
+		public function set x2(x:Number):void { _x2 = x; dirty(); }
+
+		/** The y-coordinate for the second line endpoint. */		
+		public function get y2():Number  { return _y2; }
+		public function set y2(y:Number):void { _y2 = y; dirty(); }
+		
+		/** The color of the line. */
+		public function get lineColor():uint  { return _color; }
+		public function set lineColor(c:uint):void { _color = c; dirty(); }
+		
+		/** The width of the line. A value of zero indicates a hairwidth line,
+		 *  as determined by <code>Graphics.lineStyle</code> */
+		public function get lineWidth():Number  { return _width; }
+		public function set lineWidth(w:Number):void { _width = w; dirty(); }
+		
+		public override function render():void
+		{
+			graphics.clear();
+			graphics.lineStyle(_width, _color, 1, true, "none");
+			graphics.moveTo(_x1, _y1);
+			graphics.lineTo(_x2, _y2);
+		}
+		
+	} // end of class LineSprite
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/DirtySprite.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/DirtySprite.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/DirtySprite.as	(revision 15)
@@ -0,0 +1,270 @@
+package gssim.gssimstudio.editor.flare.display
+{
+	import flash.display.DisplayObject;
+	import flash.display.Sprite;
+	import flash.display.Stage;
+	import flash.events.Event;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	
+	/**
+	 * A Sprite that redraws itself as needed when marked as "dirty".
+	 * This allows multiple changes to be made to the sprite between frames
+	 * without triggering a potentially costly redraw for each property update.
+	 * Instead, the <code>dirty()</code> method should be called whenever a
+	 * change is made to the Sprite that would normally require a redraw. This
+	 * class will ensure that the Sprite is redrawn only once before the next
+	 * frame is rendered.
+	 * 
+	 * <p>Subclasses should place drawing code within the <code>render()</code>
+	 * method. For all properties used by the <code>render</code> method to help
+	 * draw this sprite, the corresponding "setter" method should call the
+	 * <code>dirty()</code> method to mark the sprite as dirty and thereby
+	 * trigger a redraw for the next frame.</p>
+	 * 
+	 * <p>Internally, the DirtySprite class maintains a static list of all
+	 * "dirty" sprites, and redraws each sprite in the list when a
+	 * <code>Event.RENDER</code> event is issued. Typically, this process is
+	 * performed automatically. In a few cases, erratic behavior has been
+	 * observed due to a Flash Player bug that results in <code>RENDER</code>
+	 * events not being properly issued. As a fallback, the static
+	 * <code>renderDirty()</code> method can be invoked to manually force
+	 * each dirty sprite to be redrawn.</p>
+	 */
+	public class DirtySprite extends Sprite
+	{
+		private static var __stage:Stage;
+		private static var __installed:Boolean = false;
+		private static var __dirtyList:Array = [];
+		
+		/**
+		 * Installs the frame render listener on the stage.
+		 */	
+		private static function install(stage:Stage):void
+		{
+			__stage = stage;
+			__stage.addEventListener(Event.RENDER, renderDirty);
+			__installed = true;
+		}
+		
+		/**
+		 * Frame render callback that renders all sprites on the dirty list.
+		 * Typically, this method is automatically triggered by stage
+		 * RENDER events. It can also be manually invoked to redraw all
+		 * dirty DirtySprites.
+		 * @param evt the event that triggered the rendering (can be null)
+		 */
+		public static function renderDirty(evt:Event=null):void
+		{
+			while (__dirtyList.length > 0) {
+				var ds:DirtySprite = DirtySprite(__dirtyList.pop());
+				var db:Boolean = (ds._dirty == DIRTY);
+				ds._dirty = CLEAN;
+				if (db) ds.render();
+			}
+
+			// We need to remove and then re-add the listeners
+			// to work around Flash Player bugs (#139381?). Ugh.
+			// TODO: it seems this is not a complete solution, as in
+			// rare cases RENDER events are still omitted.
+			if (__stage != null) {
+				__stage.removeEventListener(Event.RENDER, renderDirty);
+				__installed = false;
+			}
+		}
+		
+		// --------------------------------------------------------------------
+		
+		private static const CLEAN:int = 0; // no changes
+		private static const DIRTY:int = 1; // re-rendering needed
+		private static const VISIT:int = 2; // was re-rendered, but on list
+		
+		/** @private */
+		protected var _dirty:int = DIRTY; // dirty at birth
+		
+		/**
+		 * Creates a new DirtySprite. Registers this Sprite to receive
+		 * added-to-stage events.
+		 */
+		public function DirtySprite() {
+			this.addEventListener(Event.ADDED_TO_STAGE, onAddToStage,
+								  false, 0, true); // use weak reference
+			__dirtyList.push(this);
+		}
+		
+		/**
+		 * Makes sure that "dirtying" changes made to this Sprite
+		 * while it is off the display list still result in a
+		 * re-rendering if the Sprite is ever added to the list.
+		 */
+		private function onAddToStage(evt:Event):void
+		{
+			if (_dirty == DIRTY) {
+				if (!__installed) install(stage);	
+				stage.invalidate();
+			}
+		}
+
+		/**
+		 * Marks this sprite as "dirty" and in need of re-rendering.
+		 * The next time that (a) a new frame is rendered, and
+		 * (b) this Sprite is on the display list, the render method
+		 * will automatically be called.
+		 */
+		public final function dirty():void
+		{
+			if (_dirty == DIRTY) return;
+			
+			__dirtyList.push(this);
+			if (stage) {	
+				if (!__installed) install(stage);
+				stage.invalidate();
+			}
+			_dirty = DIRTY;
+		}
+		
+		/**
+		 * If dirty, this sprite is re-rendered before returning the width.
+		 */
+		public override function get width():Number
+		{
+			if (_dirty == DIRTY) { _dirty = VISIT; render(); }
+			return super.width;
+		}
+		
+		/**
+		 * If dirty, this sprite is re-rendered before returning the height.
+		 */
+		public override function get height():Number
+		{
+			if (_dirty == DIRTY) { _dirty = VISIT; render(); }
+			return super.height;
+		}
+		
+		/**
+		 * If dirty, this sprite is re-rendered before returning the rect.
+		 */
+		public override function getRect(targetCoordinateSpace:DisplayObject):Rectangle
+		{
+			if (_dirty == DIRTY) { _dirty = VISIT; render(); }
+			return super.getRect(targetCoordinateSpace);
+		}
+		
+		/**
+		 * If dirty, this sprite is re-rendered returning the bounds.
+		 */
+		public override function getBounds(targetCoordinateSpace:DisplayObject):Rectangle
+		{
+			if (_dirty == DIRTY) { _dirty = VISIT; render(); }
+			return super.getBounds(targetCoordinateSpace);
+		}
+		
+		/**
+		 * If dirty, either sprite is re-rendered before hit-testing.
+		 */
+		public override function hitTestObject(obj:DisplayObject):Boolean
+		{
+			if (_dirty == DIRTY) { _dirty = VISIT; render(); }
+			var ds:DirtySprite = obj as DirtySprite;
+			if (ds && ds._dirty == DIRTY) { ds._dirty = VISIT; ds.render(); }
+			return super.hitTestObject(obj);
+		}
+		
+		/**
+		 * If dirty, this sprite is re-rendered before hit-testing.
+		 */
+		public override function hitTestPoint(x:Number, y:Number, shapeFlag:Boolean=false):Boolean
+		{
+			if (_dirty == DIRTY) { _dirty = VISIT; render(); }
+			return super.hitTestPoint(x, y, shapeFlag);
+		}
+		
+		/**
+		 * Draw this sprite's graphical content. Subclasses should
+		 * override this method with custom drawing code.
+		 */
+		public function render():void
+		{
+			// for sub-classes to override...
+		}
+		
+		/** @inheritDoc */
+		public override function toString():String
+		{
+			var s:String = super.toString();
+			return name==null ? s : s + " \""+name+"\"";
+		}
+		
+		
+		// -- Polar Coordinates -----------------------------------------------
+		
+		/** A constant for the point (0,0). */
+		public static const ZERO:Point = new Point(0,0);
+		
+		/** The radius value of this sprite's position in polar co-ordinates.
+		 *  Polar coordinate values are assume a circle center given by the
+		 *  <code>origin</code> property. */
+		protected var _radius:Number;
+		
+		/** The angle value of this sprite's position in polar co-ordinates.
+		 *  Polar coordinate values are assume a circle center given by the
+		 *  <code>origin</code> property. */
+		protected var _angle:Number;
+		
+		/** The origin point for polar coordinates. */
+		protected var _origin:Point = ZERO;
+		
+		/** @inheritDoc */
+		public override function set x(v:Number):void {
+			super.x = v; _radius = NaN; _angle = NaN;
+		}
+		/** @inheritDoc */
+		public override function set y(v:Number):void {
+			super.y = v; _radius = NaN; _angle = NaN;
+		}
+		
+		/** The radius value of this sprite's position in polar co-ordinates.
+		 *  Polar coordinate values are assume a circle center given by the
+		 *  <code>origin</code> property. */
+		public function get radius():Number {
+			if (isNaN(_radius)) {
+				var cx:Number = x - _origin.x;
+				var cy:Number = y - _origin.y;
+				_radius = Math.sqrt(cx*cx + cy*cy);
+			}
+			return _radius;
+		}
+		public function set radius(r:Number):void {
+			var a:Number = angle;
+			super.x =  r * Math.cos(a) + _origin.x;
+			super.y = -r * Math.sin(a) + _origin.y;
+			_radius = r;
+		}
+		
+		/** The angle value of this sprite's position in polar co-ordinates.
+		 *  Polar coordinate values are assume a circle center given by the
+		 *  <code>origin</code> property. */
+		public function get angle():Number {
+			if (isNaN(_angle)) {
+				_angle = Math.atan2(-(y-_origin.y),(x-_origin.x));
+			}
+			return _angle;
+		}
+		public function set angle(a:Number):void {
+			var r:Number = radius;
+			super.x =  r * Math.cos(a) + _origin.x;
+			super.y = -r * Math.sin(a) + _origin.y;
+			_angle = a;
+		}
+		
+		/** The origin point for polar coordinates. */
+		public function get origin():Point { return _origin; }
+		public function set origin(p:Point):void {
+			if (p.x != _origin.x || p.y != _origin.y) {
+				_radius = NaN; _angle = NaN;
+			}
+			_origin = p;
+		}
+		
+	} // end of class DirtySprite
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/RectSprite.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/RectSprite.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/RectSprite.as	(revision 15)
@@ -0,0 +1,107 @@
+package gssim.gssimstudio.editor.flare.display
+{
+	import gssim.gssimstudio.editor.flare.util.Colors;
+	
+	/**
+	 * A Sprite representing a rectangle shape. Supports line and fill colors
+	 * and rounded corners.
+	 */
+	public class RectSprite extends DirtySprite
+	{
+		/** @private */
+		protected var _w:Number;
+		/** @private */
+		protected var _h:Number;
+		/** @private */
+		protected var _cw:Number = 0;
+		/** @private */
+		protected var _ch:Number = 0;
+		/** @private */
+		protected var _fillColor:uint = 0x00ffffff;
+		/** @private */
+		protected var _lineColor:uint = 0xffaaaaaa;
+		/** @private */
+		protected var _lineWidth:Number = 0;
+		/** @private */
+		protected var _pixelHinting:Boolean = true;
+		
+		/** The width of the rectangle. */
+		public function get w():Number { return _w; }
+		public function set w(v:Number):void { _w = v; dirty(); }
+		
+		/** The height of the rectangle. */
+		public function get h():Number { return _h; }
+		public function set h(v:Number):void { _h = v; dirty(); }
+		
+		/** The width of rounded corners. Zero indicates no rounding. */
+		public function get cornerWidth():Number { return _cw; }
+		public function set cornerWidth(v:Number):void { _cw = v; dirty(); }
+		
+		/** The height of rounded corners. Zero indicates no rounding. */
+		public function get cornerHeight():Number { return _ch; }
+		public function set cornerHeight(v:Number):void { _ch = v; dirty(); }
+		
+		/** Sets corner width and height simultaneously. */
+		public function set cornerSize(v:Number):void { _cw = _ch = v; dirty(); }
+		
+		/** The fill color of the rectangle. */
+		public function get fillColor():uint { return _fillColor; }
+		public function set fillColor(c:uint):void { _fillColor = c; dirty(); }
+		
+		/** The line color of the rectangle outline. */
+		public function get lineColor():uint { return _lineColor; }
+		public function set lineColor(c:uint):void { _lineColor = c; dirty(); }
+		
+		/** The line width of the rectangle outline. */
+		public function get lineWidth():Number { return _lineWidth; }
+		public function set lineWidth(v:Number):void { _lineWidth = v; dirty(); }
+		
+		/** Flag indicating if pixel hinting should be used for the outline. */
+		public function get linePixelHinting():Boolean { return _pixelHinting; }
+		public function set linePixelHinting(b:Boolean):void {
+			_pixelHinting = b; dirty();
+		}
+				
+		/**
+		 * Creates a new RectSprite.
+		 * @param x the x-coordinate of the top-left corner of the rectangle
+		 * @param y the y-coordinate of the top-left corder of the rectangle
+		 * @param w the width of the rectangle
+		 * @param h the height of the rectangle
+		 * @param cw the width of rounded corners (zero for no rounding)
+		 * @param ch the height of rounded corners (zero for no rounding)
+		 */
+		public function RectSprite(x:Number=0, y:Number=0, w:Number=0,
+			h:Number=0, cw:Number=0, ch:Number=0)
+		{
+			this.x = x;
+			this.y = y;
+			this._w = w;
+			this._h = h;
+			this._cw = cw;
+			this._ch = ch;
+		}
+		
+		/** @inheritDoc */
+		public override function render():void
+		{
+			graphics.clear();
+			if (isNaN(_w) || isNaN(_h)) return;
+			
+			var la:Number = Colors.a(_lineColor) / 255;
+			var fa:Number = Colors.a(_fillColor) / 255;
+			var lc:uint = _lineColor & 0x00ffffff;
+			var fc:uint = _fillColor & 0x00ffffff;
+
+			if (la>0) graphics.lineStyle(_lineWidth, lc, la, _pixelHinting);
+			graphics.beginFill(fc, fa);
+			if (_cw > 0 || _ch > 0) {
+				graphics.drawRoundRect(0, 0, _w, _h, _cw, _ch);
+			} else {
+				graphics.drawRect(0, 0, _w, _h);
+			}
+			graphics.endFill();
+		}
+		
+	} // end of class RectSprite
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/TextSprite.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/TextSprite.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/display/TextSprite.as	(revision 15)
@@ -0,0 +1,350 @@
+package gssim.gssimstudio.editor.flare.display
+{
+	import flash.display.Bitmap;
+	import flash.display.BitmapData;
+	import flash.display.DisplayObject;
+	import flash.geom.Rectangle;
+	import flash.text.TextField;
+	import flash.text.TextFieldAutoSize;
+	import flash.text.TextFormat;
+
+	/**
+	 * A Sprite representing a text label.
+	 * TextSprites support multiple forms of text representation: bitmapped
+	 * text, embedded font text, and standard (device font) text. This allows
+	 * flexibility in how text labels are handled. For example, by default,
+	 * text fields using device fonts do not support alpha blending or
+	 * rotation. By using a TextSprite in BITMAP mode, the text is rendered
+	 * out to a bitmap which can then be alpha blended.
+	 */
+	public class TextSprite extends DirtySprite
+	{
+		// vertical anchors
+		/**
+		 * Constant for vertically aligning the top of the text field
+		 * to a TextSprite's y-coordinate.
+		 */
+		public static const TOP:int = 0;
+		/**
+		 * Constant for vertically aligning the middle of the text field
+		 * to a TextSprite's y-coordinate.
+		 */
+		public static const MIDDLE:int = 1;
+		/**
+		 * Constant for vertically aligning the bottom of the text field
+		 * to a TextSprite's y-coordinate.
+		 */
+		public static const BOTTOM:int = 2;
+
+		// horizontal anchors
+		/**
+		 * Constant for horizontally aligning the left of the text field
+		 * to a TextSprite's y-coordinate.
+		 */
+		public static const LEFT:int = 0;
+		/**
+		 * Constant for horizontally aligning the center of the text field
+		 * to a TextSprite's y-coordinate.
+		 */
+		public static const CENTER:int = 1;
+		/**
+		 * Constant for horizontally aligning the right of the text field
+		 * to a TextSprite's y-coordinate.
+		 */
+		public static const RIGHT:int = 2;
+		
+		// text handling modes
+		/**
+		 * Constant indicating that text should be rendered using a TextField
+		 * instance using device fonts.
+		 */
+		public static const DEVICE:uint = 0;
+		/**
+		 * Constant indicating that text should be rendered using a TextField
+		 * instance using embedded fonts. For this mode to work, the fonts
+		 * used must be embedded in your application SWF file.
+		 */
+		public static const EMBED:uint = 1;
+		/**
+		 * Constant indicating that text should be rendered into a Bitmap
+		 * instance.
+		 */
+		public static const BITMAP:uint = 2;
+		
+		private var _mode:int = -1;
+		private var _bmap:Bitmap;
+		private var _tf:TextField;
+		private var _fmt:TextFormat;
+		
+		private var _hAnchor:int = LEFT;
+		private var _vAnchor:int = TOP;
+		
+		/** The TextField instance backing this TextSprite. */
+		public function get textField():TextField { return _tf; }
+		
+		/** The bitmap of the text, if in BITMAP mode. */
+		public function get bitmap():Bitmap { return _bmap; }
+		
+		/**
+		 * The text rendering mode for this TextSprite, one of BITMAP,
+		 * DEVICE, or EMBED.
+		 */
+		public function get textMode():int { return _mode; }
+		public function set textMode(mode:int):void {
+			setMode(mode);
+		}
+		
+		/** The default text format for this text sprite. */
+		public function get textFormat():TextFormat { return _fmt; }
+		public function set textFormat(fmt:TextFormat):void {
+			_tf.defaultTextFormat = (_fmt = fmt);
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The text shown by this TextSprite.
+		 */
+		public function get text():String { return _tf.text; }
+		public function set text(txt:String):void {
+			if (_tf.text != txt) {
+				_tf.text = (txt==null ? "" : txt);
+				if (_fmt!=null) _tf.setTextFormat(_fmt);
+				dirty();
+			}
+		}
+		
+		/**
+		 * The html text shown by this TextSprite.
+		 */
+		public function get htmlText():String { return _tf.htmlText; }
+		public function set htmlText(txt:String):void {
+			if (_tf.htmlText != txt) {
+				_tf.htmlText = (txt==null ? "" : txt);
+				dirty();
+			}
+		}
+		
+		/**
+		 * The font to the text.
+		 */
+		public function get font():String { return String(_fmt.font); }
+		public function set font(f:String):void {
+			_fmt.font = f;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The color of the text.
+		 */
+		public function get color():uint { return uint(_fmt.color); }
+		public function set color(c:uint):void {
+			_fmt.color = c;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The size of the text.
+		 */
+		public function get size():Number { return Number(_fmt.size); }
+		public function set size(s:Number):void {
+			_fmt.size = s;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The boldness of the text.
+		 */
+		public function get bold():Boolean { return Boolean(_fmt.bold); }
+		public function set bold(b:Boolean):void {
+			_fmt.bold = b;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The italics of the text.
+		 */
+		public function get italic():Boolean { return Boolean(_fmt.italic); }
+		public function set italic(b:Boolean):void {
+			_fmt.italic = b;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The underline of the text.
+		 */
+		public function get underline():Boolean { return Boolean(_fmt.underline); }
+		public function set underline(b:Boolean):void {
+			_fmt.underline = b;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The kerning of the text.
+		 */
+		public function get kerning():Boolean { return Boolean(_fmt.kerning); }
+		public function set kerning(b:Boolean):void {
+			_fmt.kerning = b;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The letter-spacing of the text.
+		 */
+		public function get letterSpacing():int { return int(_fmt.letterSpacing); }
+		public function set letterSpacing(s:int):void {
+			_fmt.letterSpacing = s;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/**
+		 * The horizontal anchor for the text, one of LEFT, RIGHT, or CENTER.
+		 * This setting determines how the text is horizontally aligned with
+		 * respect to this TextSprite's (x,y) location.
+		 */
+		public function get horizontalAnchor():int { return _hAnchor; }
+		public function set horizontalAnchor(a:int):void { 
+			if (_hAnchor != a) { _hAnchor = a; layout(); }
+		}
+		
+		/**
+		 * The vertical anchor for the text, one of TOP, BOTTOM, or MIDDLE.
+		 * This setting determines how the text is vertically aligned with
+		 * respect to this TextSprite's (x,y) location.
+		 */
+		public function get verticalAnchor():int { return _vAnchor; }
+		public function set verticalAnchor(a:int):void {
+			if (_vAnchor != a) { _vAnchor = a; layout(); }
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new TextSprite instance.
+		 * @param text the text string for this label
+		 * @param format the TextFormat determining font family, size, and style
+		 * @param mode the text rendering mode to use (BITMAP by default)
+		 */
+		public function TextSprite(text:String=null, format:TextFormat=null, mode:int=BITMAP) {
+			_tf = new TextField();
+			_tf.selectable = false; // not selectable by default
+			_tf.autoSize = TextFieldAutoSize.LEFT;
+			_tf.defaultTextFormat = (_fmt = format ? format : new TextFormat());
+			if (text != null) _tf.text = text;
+			_bmap = new Bitmap();
+			setMode(mode);
+			dirty();
+		}
+		
+		protected function setMode(mode:int):void
+		{
+			if (mode == _mode) return; // nothing to do
+			
+			switch (_mode) {
+				case BITMAP:
+					_bmap.bitmapData = null;
+					removeChild(_bmap);
+					break;
+				case EMBED:
+					_tf.embedFonts = false;
+				case DEVICE:
+					removeChild(_tf);
+					break;
+			}
+			switch (mode) {
+				case BITMAP:
+					rasterize();
+					addChild(_bmap);
+					break;
+				case EMBED:
+					_tf.embedFonts = true;
+				case DEVICE:
+					addChild(_tf);
+					break;
+			}
+			_mode = mode;
+		}
+		
+		/**
+		 * Applies the settings of the input text format to this sprite's
+		 * internal text format. This method makes a shallow copy of the
+		 * input format, it does not save a reference to it.
+		 * @param fmt the text format to apply
+		 */
+		public function applyFormat(fmt:TextFormat):void {
+			_fmt.align = fmt.align;
+			_fmt.blockIndent = fmt.blockIndent;
+			_fmt.bold = fmt.bold;
+			_fmt.bullet = fmt.bullet;
+			_fmt.color = fmt.color;
+			_fmt.display = fmt.display;
+			_fmt.font = fmt.font;
+			_fmt.indent = fmt.indent;
+			_fmt.italic = fmt.italic;
+			_fmt.kerning = fmt.kerning;
+			_fmt.leading = fmt.leading;
+			_fmt.leftMargin = fmt.leftMargin;
+			_fmt.letterSpacing = fmt.letterSpacing;
+			_fmt.rightMargin = fmt.rightMargin;
+			_fmt.size = fmt.size;
+			_fmt.tabStops = fmt.tabStops;
+			_fmt.target = fmt.target;
+			_fmt.underline = fmt.underline;
+			_fmt.url = fmt.url;
+			_tf.setTextFormat(_fmt);
+			if (_mode==BITMAP) dirty();
+		}
+		
+		/** @inheritDoc */
+		public override function render():void
+		{
+			if (_mode == BITMAP) {
+				rasterize();
+			}
+			layout();
+		}
+		
+		/** @private */
+		protected function layout():void
+		{
+			var d:DisplayObject = (_mode==BITMAP ? _bmap : _tf);
+			
+			// horizontal anchor
+			switch (_hAnchor) {
+				case LEFT:   d.x = 0; break;
+				case CENTER: d.x = -d.width / 2; break;
+				case RIGHT:  d.x = -d.width; break;
+			}
+			// vertical anchor
+			switch (_vAnchor) {
+				case TOP:    d.y = 0; break;
+				case MIDDLE: d.y = -d.height / 2; break;
+				case BOTTOM: d.y = -d.height; break;
+			}
+		}
+		
+		/** @private */
+		protected function rasterize():void
+		{
+			var tw:Number = _tf.width + 1;
+			var th:Number = _tf.height + 1;
+			var bd:BitmapData = _bmap.bitmapData;
+			if (bd == null || bd.width != tw || bd.height != th) {
+				bd = new BitmapData(tw, th, true, 0x00ffffff);
+				_bmap.bitmapData = bd;
+			} else {
+				bd.fillRect(new Rectangle(0,0,tw,th), 0x00ffffff);
+			}
+			bd.draw(_tf);
+		}
+		
+	} // end of class TextSprite
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Variable.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Variable.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Variable.as	(revision 15)
@@ -0,0 +1,54 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	import gssim.gssimstudio.editor.flare.util.Property;
+	
+	/**
+	 * Expression operator that retrieves a value from an object property.
+	 * Uses a <code>flare.util.Property</code> instance to access the value.
+	 * @see flare.util.Property
+	 */
+	public class Variable extends Expression
+	{
+		/** @private */
+		protected var _prop:Property;
+		
+		/** The name of the variable property. */
+		public function get name():String { return _prop.name; }
+		public function set name(f:String):void {
+			_prop = Property.$(f);
+		}
+		
+		/**
+		 * Creates a new Variable operator.
+		 * @param name the name of the variable property
+		 */
+		public function Variable(name:String) {
+			this.name = name;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new Variable(_prop.name);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return _prop.getValue(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function toString():String
+		{
+			return "`"+_prop.name+"`";
+		}
+		
+	} // end of class Variable
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Variance.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Variance.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Variance.as	(revision 15)
@@ -0,0 +1,70 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Aggregate operator for computing variance or standard deviation.
+	 */
+	public class Variance extends AggregateExpression
+	{
+		/** Flag indicating the population variance or deviation. */
+		public static const POPULATION:int = 0;
+		/** Flag indicating the sample variance or deviation. */
+		public static const SAMPLE:int     = 2;
+		/** Flag indicating the variance should be computed. */
+		public static const VARIANCE:int   = 0;
+		/** Flag indicating the standard deviation should be computed. */
+		public static const DEVIATION:int  = 1;
+		
+		private var _type:int;
+		private var _sum:Number;
+		private var _accum:Number;
+		private var _count:Number;
+		
+		/**
+		 * Creates a new Variance operator. By default, the population variance
+		 * is computed. Use the type flags to change this. For example, the type
+		 * argument <code>Variance.SAMPLE | Variance.DEVIATION</code> results in
+		 * the sample standard deviation being computed.
+		 * @param input the sub-expression of which to compute variance
+		 * @param type the type of variance or deviation to compute
+		 */
+		public function Variance(input:*, type:int=0) {
+			super(input);
+			_type = type;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function reset():void
+		{
+			_sum = 0;
+			_accum = 0;
+			_count = 0;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			var n:Number = _count - (_type & SAMPLE ? 1 : 0);
+			var v:Number = _sum / n;
+			v = v*v + _accum / n;
+			return (_type & DEVIATION ? Math.sqrt(v) : v);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function aggregate(value:Object):void
+		{
+			var x:Number = Number(_expr.eval(value));
+			if (!isNaN(x)) {
+				_sum += x;
+				_accum += x*x;
+				_count += 1;
+			}
+		}
+		
+	} // end of class Variance
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Count.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Count.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Count.as	(revision 15)
@@ -0,0 +1,45 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Aggregate operator for counting the number of items in a set of values.
+	 */
+	public class Count extends AggregateExpression
+	{
+		private var _count:int;
+		
+		/**
+		 * Creates a new Count operator
+		 * @param input the sub-expression of which to count the value
+		 */
+		public function Count(input:*) {
+			super(input);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function reset():void
+		{
+			_count = 0;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return _count;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function aggregate(value:Object):void
+		{
+			if (_expr.eval(value) != null) {
+				_count++;
+			}
+		}
+		
+	} // end of class Count
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Arithmetic.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Arithmetic.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Arithmetic.as	(revision 15)
@@ -0,0 +1,132 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Expression operator for arithmetic operations. Performs addition,
+	 * subtraction, multiplication, or division of sub-expression values.
+	 */
+	public class Arithmetic extends BinaryExpression
+	{
+		/** Indicates an addition operation. */
+	    public static const ADD:int = 0;
+	    /** Indicates a subtraction operation. */
+	    public static const SUB:int = 1;
+	    /** Indicates a multiplication operation. */
+	    public static const MUL:int = 2;
+	    /** Indicates a division operation. */
+	    public static const DIV:int = 3;
+	    /** Indicates a modulo operation. */
+	    public static const MOD:int = 4;
+		
+		/** Returns a string representation of the arithmetic operator. */
+		public override function get operatorString():String
+		{
+        	switch (_op) {
+	        	case ADD: return '+';
+	        	case SUB: return '-';
+	        	case MUL: return '*';
+	        	case DIV: return '/';
+	        	case MOD: return '%';
+	        	default: return '?';
+	        }
+		}
+		
+		/**
+	     * Create a new Arithmetic expression.
+	     * @param operation the operation to perform
+	     * @param left the left sub-expression
+	     * @param right the right sub-expression
+	     */
+	    public function Arithmetic(op:int, left:*, right:*)
+	    {
+	        super(op, ADD, MOD, left, right);
+	    }
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new Arithmetic(_op, _left.clone(), _right.clone());
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			var x:Number = Number(_left.eval(o));
+			var y:Number = Number(_right.eval(o));
+			
+	        // compute return value
+	        switch (_op) {
+	        	case ADD: return x+y;
+	        	case SUB: return x-y;
+	        	case MUL: return x*y;
+	        	case DIV: return x/y;
+	        	case MOD: return x%y;
+	        }
+	        throw new Error("Unknown operation type: "+_op);
+		}
+		
+		// -- Static constructors ---------------------------------------------
+		
+		/**
+		 * Creates a new Arithmetic operator for adding two numbers.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Arithmetic operator
+		 */
+		public static function Add(left:*, right:*):Arithmetic
+		{
+			return new Arithmetic(ADD, left, right);
+		}
+		
+		/**
+		 * Creates a new Arithmetic operator for subtracting one number
+		 *  from another.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Arithmetic operator
+		 */
+		public static function Subtract(left:*, right:*):Arithmetic
+		{
+			return new Arithmetic(SUB, left, right);
+		}
+		
+		/**
+		 * Creates a new Arithmetic operator for multiplying two numbers.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Arithmetic operator
+		 */
+		public static function Multiply(left:*, right:*):Arithmetic
+		{
+			return new Arithmetic(MUL, left, right);
+		}
+		
+		/**
+		 * Creates a new Arithmetic operator for dividing one number
+		 *  by another.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Arithmetic operator
+		 */
+		public static function Divide(left:*, right:*):Arithmetic
+		{
+			return new Arithmetic(DIV, left, right);
+		}
+		
+		/**
+		 * Creates a new Arithmetic operator for computing the modulo
+		 *  (remainder) of a number.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Arithmetic operator
+		 */
+		public static function Mod(left:*, right:*):Arithmetic
+		{
+			return new Arithmetic(MOD, left, right);
+		}
+		
+	} // end of class Arithmetic
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Range.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Range.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Range.as	(revision 15)
@@ -0,0 +1,51 @@
+package gssim.gssimstudio.editor.flare.query
+{	
+	/**
+	 * Expression operator that tests if a value is within a given range.
+	 * Implemented as an <code>And</code> of <code>Comparison</code>
+	 * expressions.
+	 */
+	public class Range extends And
+	{
+		/** Sub-expression for the minimum value of the range. */
+		public function get min():Expression { return _children[0].left; }
+		public function set min(e:*):void {
+			_children[0].left = Expression.expr(e);
+		}
+		
+		/** Sub-expression for the maximum value of the range. */
+		public function get max():Expression { return _children[1].right; }
+		public function set max(e:*):void {
+			_children[1].right = Expression.expr(e);
+		}
+		
+		/** Sub-expression for the value to test for range inclusion. */
+		public function get val():Expression { return _children[0].right; }
+		public function set val(e:*):void {
+			var expr:Expression = Expression.expr(e);
+			_children[0].right = expr;
+			_children[1].left = expr;
+		}
+		
+		/**
+		 * Create a new Range operator.
+		 * @param min sub-expression for the minimum value of the range
+		 * @param max sub-expression for the maximum value of the range
+		 * @param val sub-expression for the value to test for range inclusion
+		 */
+		public function Range(min:*, max:*, val:*)
+		{
+			addChild(new Comparison(Comparison.LTEQ, min, val));
+			addChild(new Comparison(Comparison.LTEQ, val, max));
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new Range(min.clone(), max.clone(), val.clone());
+		}
+		
+	} // end of class RangePredicate
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Match.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Match.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Match.as	(revision 15)
@@ -0,0 +1,127 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Expression operator for text matching operations. Performs prefix,
+	 * suffix, containment, and regular expression matching.
+	 */
+	public class Match extends BinaryExpression
+	{
+		/** Indicates a prefix matching test. */
+	    public static const PREFIX:int = 0;
+	    /** Indicates a suffix matching test. */
+	    public static const SUFFIX:int = 1;
+	    /** Indicates a string containment test. */
+	    public static const WITHIN:int = 2;
+	    /** Indicates a regular expression matching test. */
+	    public static const REGEXP:int = 3;
+		
+		/** Returns a string representation of the string matching operator. */
+		public override function get operatorString():String
+		{
+        	switch (_op) {
+	        	case PREFIX: return 'STARTS-WITH';
+	        	case SUFFIX: return 'ENDS-WITH';
+	        	case WITHIN: return 'CONTAINS';
+	        	case REGEXP: return 'REGEXP';
+	        	default: return '?';
+	        }
+		}
+		
+		/**
+	     * Create a new Match expression.
+	     * @param operation the operation to perform
+	     * @param left the left sub-expression
+	     * @param right the right sub-expression
+	     */
+	    public function Match(op:int, left:*, right:*)
+	    {
+	        super(op, PREFIX, REGEXP, left, right);
+	    }
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new Match(_op, _left.clone(), _right.clone());
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			var s:String = String(_left.eval(o));
+			var p:String = String(_right.eval(o));
+			
+	        // compute return value
+	        switch (_op) {
+	        	case PREFIX: return StringUtil.startsWith(s, p);
+	        	case SUFFIX: return StringUtil.endsWith(s, p);
+	        	case WITHIN: return s.indexOf(p) >= 0;
+	        	case REGEXP: return parseRegExp(p).test(s);
+	        }
+	        throw new Error("Unknown operation type: "+_op);
+		}
+		
+		private var cachedRegExp:RegExp;
+		private var cachedPattern:String;
+		
+		private function parseRegExp(p:String):RegExp
+		{
+			if (p == cachedPattern) return cachedRegExp;
+			
+			cachedPattern = p;
+			var tok:Array = p.split("/");
+			cachedRegExp = new RegExp(tok[1], tok[2]);
+			return cachedRegExp;
+		}
+		
+		// -- Static constructors ---------------------------------------------
+		
+		/**
+		 * Creates a new Match operator for matching string prefix.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Match operator
+		 */
+		public static function StartsWith(left:*, right:*):Match
+		{
+			return new Match(PREFIX, left, right);
+		}
+		
+		/**
+		 * Creates a new Match operator for matching a string suffix.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Match operator
+		 */
+		public static function EndsWith(left:*, right:*):Match
+		{
+			return new Match(SUFFIX, left, right);
+		}
+		
+		/**
+		 * Creates a new Match operator for matching string containment.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Match operator
+		 */
+		public static function Contains(left:*, right:*):Match
+		{
+			return new Match(WITHIN, left, right);
+		}
+		
+		/**
+		 * Creates a new Match operator for matching a regular expression.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Match operator
+		 */
+		public static function RegEx(left:*, right:*):Match
+		{
+			return new Match(REGEXP, left, right);
+		}
+		
+	} // end of class Match
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Literal.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Literal.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Literal.as	(revision 15)
@@ -0,0 +1,60 @@
+package gssim.gssimstudio.editor.flare.query
+{	
+	/**
+	 * Expression operator for a literal value.
+	 */
+	public class Literal extends Expression
+	{
+		/** The boolean true literal. */
+		public static const TRUE:Literal = new Literal(true);
+		/** The boolean false literal. */
+		public static const FALSE:Literal = new Literal(false);
+		
+		private var _value:Object = null;
+		
+		/** The literal value of this expression. */
+		public function get value():Object { return _value; }
+		public function set value(val:Object):void { _value = val; }
+		
+		/**
+		 * Creates a new Literal instance.
+		 * @param val the literal value
+		 */
+		public function Literal(val:Object=null) {
+			_value = val;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new Literal(_value);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function predicate(o:Object):Boolean
+		{
+			return Boolean(_value);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return _value;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function toString():String
+		{
+			return String(_value);
+		}
+		
+	} // end of class Literal
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/If.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/If.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/If.as	(revision 15)
@@ -0,0 +1,106 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Expression operator for an if statement that performs conditional
+	 * execution.
+	 */
+	public class If extends Expression
+	{
+		private var _test:Expression;
+    	private var _then:Expression;
+    	private var _else:Expression;
+	    
+	    /** The conditional clause of the if statement. */
+	    public function get test():Expression { return _test; }
+	    public function set test(e:*):void {
+	    	_test = Expression.expr(e);
+	    }
+	    
+	    /** Sub-expression evaluated if the test condition is true. */
+	    public function get then():Expression { return _then; }
+	    public function set then(e:*):void {
+	    	_then = Expression.expr(e);
+	    }
+	    
+	    /** Sub-expression evaluated if the test condition is false. */
+	    public function get els():Expression { return _else; }
+	    public function set els(e:*):void {
+	    	_else = Expression.expr(e);
+	    }
+	    
+	    /**
+		 * @inheritDoc
+		 */
+	    public override function get numChildren():int { return 3; }
+	    
+	    // --------------------------------------------------------------------
+	    
+	    /**
+	     * Create a new IfExpression.
+	     * @param test the test expression for the if statement
+	     * @param thenExpr the expression to evaluate if the test predicate
+	     * evaluates to true
+	     * @param elseExpr the expression to evaluate if the test predicate
+	     * evaluates to false
+	     */
+	    public function If(test:*, thenExpr:*, elseExpr:*)
+	    {
+	        this.test = test;
+	        this.then = thenExpr;
+	        this.els = elseExpr;
+	    }
+	    
+	    /**
+		 * @inheritDoc
+		 */
+	    public override function clone():Expression
+		{
+			return new If(_test.clone(), _then.clone(), _else.clone());
+		}
+	    
+	    /**
+		 * @inheritDoc
+		 */
+	    public override function eval(o:Object=null):*
+		{
+			return (_test.predicate(o) ? _then : _else).eval(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function getChildAt(idx:int):Expression
+		{
+			switch (idx) {
+				case 0: return _test;
+				case 1: return _then;
+				case 2: return _else;
+				default: return null;
+			}
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function setChildAt(idx:int, expr:Expression):Boolean
+		{
+			switch (idx) {
+				case 0: _test = expr; return true;
+				case 1: _then = expr; return true;
+				case 2: _else = expr; return true;
+				default: return false;
+			}
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+	    public override function toString():String
+	    {
+	        return "IF " + _test.toString()
+	            + " THEN " + _then.toString()
+	            + " ELSE " + _else.toString();
+	    }
+		
+	} // end of class If
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Expression.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Expression.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Expression.as	(revision 15)
@@ -0,0 +1,160 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	import gssim.gssimstudio.editor.flare.util.IEvaluable;
+	import gssim.gssimstudio.editor.flare.util.IPredicate;
+		
+	/**
+	 * Base class for query expression operators. Expressions are organized
+	 * into a tree of operators that perform data processing or predicate
+	 * testing on input <code>Object</code> instances.
+	 */
+	public class Expression implements IEvaluable, IPredicate
+	{	
+		/**
+		 * Evaluates this expression with the given input object.
+		 * @param o the input object to this expression
+		 * @return the result of evaluating the expression
+		 */
+		public function eval(o:Object=null):*
+		{
+			return o;
+		}
+		
+		/**
+		 * Boolean predicate that tests the output of evaluating this
+		 * expression. Returns true if the expression evaluates to true, or
+		 * a non-null or non-zero value. Returns false if the expression
+		 * evaluates to false, or a null or zero value.
+		 * @param o the input object to this expression
+		 * @return the Boolean result of evaluating the expression
+		 */
+		public function predicate(o:Object):Boolean
+		{
+			return Boolean(eval(o));
+		}
+		
+		/**
+		 * The number of sub-expressions that are children of this expression.
+		 * @return the number of child expressions.
+		 */
+		public function get numChildren():int
+		{
+			return 0;
+		}
+		
+		/**
+		 * Returns the sub-expression at the given index.
+		 * @param idx the index of the child sub-expression
+		 * @return the requested sub-expression.
+		 */
+		public function getChildAt(idx:int):Expression
+		{
+			return null;
+		}
+		
+		/**
+		 * Set the sub-expression at the given index.
+		 * @param idx the index of the child sub-expression
+		 * @param expr the sub-expression to set
+		 * @return true if the the sub-expression was successfully set,
+		 *  false otherwise
+		 */
+		public function setChildAt(idx:int, expr:Expression):Boolean
+		{
+			return false;
+		}
+		
+		/**
+		 * Returns a string representation of the expression.
+		 * @return this expression as a string value
+		 */
+		public function toString():String
+		{
+			return null;
+		}
+		
+		/**
+		 * Creates a cloned copy of the expression. Recursively clones any
+		 * sub-expressions.
+		 * @return the cloned expression.
+		 */
+		public function clone():Expression
+		{
+			throw new Error("This is an abstract method");
+		}
+		
+		/**
+		 * Sequentially invokes the input function on this expression and all
+		 * sub-expressions. Complete either when all expressions have been
+		 * visited or the input function returns true, thereby signalling an
+		 * early exit.
+		 * @param f the visiting function to invoke on this expression
+		 * @return true if the input function signalled an early exit
+		 */
+		public function visit(f:Function):Boolean
+		{
+			var iter:ExpressionIterator = new ExpressionIterator(this);
+			return visitHelper(iter, f);
+		}
+		
+		private function visitHelper(iter:ExpressionIterator, f:Function):Boolean
+		{
+			if (f(iter.current) as Boolean) return true;
+			if (iter.down() != null)
+			{
+				do {
+					if (visitHelper(iter, f)) return true;
+				} while (iter.next() != null);
+				iter.up();	
+			}
+			return false;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		private static const _LBRACE:Number = "{".charCodeAt(0);
+		private static const _RBRACE:Number = "}".charCodeAt(0);
+		private static const _SQUOTE:Number = "'".charCodeAt(0);
+		private static const _DQUOTE:Number = "\"".charCodeAt(0);
+		
+		/**
+		 * Utility method that maps an input value into an Expression. If the
+		 * input value is already an Expression, it is simply returned. If the
+		 * input value is a String, it is interpreted as either a variable or
+		 * string literal. If the first and last characters of the string are
+		 * single quotes (') or double quotes ("), the characters between the
+		 * quotes will be used as a string Literal. If there are no quotes, or
+		 * if the string is enclosed by curly braces ({}), the string value
+		 * (sans braces) will be used as the property name of a new Variable.
+		 * In all other cases (Numbers, Dates, etc), a new Literal expression
+		 * for the input value is returned.
+		 * @param o the input value
+		 * @return an Expression corresponding to the input value
+		 */
+		public static function expr(o:*):Expression
+		{
+			if (o is Expression) {
+				return o as Expression;
+			} else if (o is Class) {
+				return new IsA(Class(o));
+			} else if (o is String) {
+				var s:String = o as String;
+				var c1:Number = s.charCodeAt(0);
+				var c2:Number = s.charCodeAt(s.length-1);
+				
+				if (c1 == _LBRACE && c2 == _RBRACE) { // braces -> variable
+					return new Variable(s.substr(1, s.length-2));
+				} else if (c1 == _SQUOTE && c2 == _SQUOTE) { // quote -> string
+					return new Literal(s.substr(1, s.length-2));
+				} else if (c1 == _DQUOTE && c2 == _DQUOTE) { // quote -> string
+					return new Literal(s.substr(1, s.length-2));
+				} else { // default -> variable
+					return new Variable(s);
+				}
+			} else {
+				return new Literal(o);
+			}
+		}
+		
+	} // end of class Expression
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Not.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Not.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Not.as	(revision 15)
@@ -0,0 +1,80 @@
+package gssim.gssimstudio.editor.flare.query
+{	
+	/**
+	 * Expression operator that returns the logical "not" of a sub-expression.
+	 */
+	public class Not extends Expression
+	{
+		private var _clause:Expression;
+		
+		/** The sub-expression clause to negate. */
+		public function get clause():Expression { return _clause; }
+		public function set clause(e:*):void { _clause = Expression.expr(e); }
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function get numChildren():int { return 1; }
+		
+		/**
+		 * Creates a new Not operator.
+		 * @param clause the sub-expression clause to negate
+		 */
+		public function Not(clause:*) {
+			_clause = Expression.expr(clause);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new Not(_clause.clone());
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return predicate(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function predicate(o:Object):Boolean
+		{
+			return !_clause.eval(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function getChildAt(idx:int):Expression
+		{
+			return (idx==0 ? _clause : null);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function setChildAt(idx:int, expr:Expression):Boolean
+		{
+			if (idx == 0) {
+				_clause = expr;
+				return true;
+			}
+			return false;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function toString():String
+		{
+			return "NOT " + _clause.toString();
+		}
+		
+	} // end of class Not
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/not.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/not.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/not.as	(revision 15)
@@ -0,0 +1,16 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Not;
+
+	/**
+	 * Creates a new <code>Not</code> query operator.
+	 * @param x the expression to negate
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function not(x:*):Not
+	{
+		return new Not(x);
+	}	
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/and.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/and.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/and.as	(revision 15)
@@ -0,0 +1,16 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.And;
+	
+	/**
+	 * Creates a new <code>And</code> query operator.
+	 * @param rest a list of expressions to include in the and
+	 * @return the new query operator
+	 */
+	public function and(...rest):And
+	{
+		var a:And = new And();
+		a.setChildren(rest);
+		return a;
+	}	
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/sum.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/sum.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/sum.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Sum;
+	
+	/**
+	 * Creates a new 'sum' <code>Arithmetic</code> query operator.
+	 * @param expr the input expression
+	 * @return the new query operator
+	 */
+	public function sum(expr:*):Sum
+	{
+		return new Sum(expr);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/iff.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/iff.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/iff.as	(revision 15)
@@ -0,0 +1,22 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.If;
+	
+	/**
+	 * Creates a new <code>If</code> query operator.
+	 * @param test the if test expression. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param then the then case expression
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param els the else case expression
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function iff(test:*, then:*, els:*):If
+	{
+		return new If(test, then, els);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/eq.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/eq.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/eq.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Comparison;
+	
+	/**
+	 * Creates a new equality <code>Comparison</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function eq(a:*, b:*):Comparison
+	{
+		return Comparison.Equal(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/xor.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/xor.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/xor.as	(revision 15)
@@ -0,0 +1,16 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Xor;
+	
+	/**
+	 * Creates a new <code>Xor</code> (exclusive or) query operator.
+	 * @param rest a list of expressions to include in the exclusive or
+	 * @return the new query operator
+	 */
+	public function xor(...rest):Xor
+	{
+		var x:Xor = new Xor();
+		x.setChildren(rest);
+		return x;
+	}	
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/average.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/average.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/average.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Average;
+	
+	/**
+	 * Creates a new <code>Average</code> query operator.
+	 * @param expr the input expression
+	 * @return the new query operator
+	 */
+	public function average(expr:*):Average
+	{
+		return new Average(expr);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/mod.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/mod.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/mod.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Arithmetic;
+
+	/**
+	 * Creates a new modulo <code>Arithmetic</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function mod(a:*, b:*):Arithmetic
+	{
+		return Arithmetic.Mod(a, b);
+	}	
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/select.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/select.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/select.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Query;
+	
+	/**
+	 * Create a new <code>Query</code> with the given select clauses.
+	 * @param terms a list of select clauses
+	 * @return the created query.
+	 */
+	public function select(...terms):Query
+	{
+		return new Query(terms);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/distinct.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/distinct.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/distinct.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Distinct;
+	
+	/**
+	 * Creates a new <code>Distinct</code> query operator.
+	 * @param expr the input expression
+	 * @return the new query operator
+	 */
+	public function distinct(expr:*):Distinct
+	{
+		return new Distinct(expr);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/update.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/update.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/update.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Query;
+	
+	/**
+	 * Create a new <code>Query</code> with the given update clauses.
+	 * @param terms a list of update clauses
+	 * @return the created query.
+	 */
+	public function update(...terms):Query
+	{
+		return new Query().update(terms);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/min.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/min.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/min.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Minimum;
+	
+	/**
+	 * Creates a new <code>Minimum</code> query operator.
+	 * @param expr the input expression
+	 * @return the new query operator
+	 */
+	public function min(expr:*):Minimum
+	{
+		return new Minimum(expr);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/neq.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/neq.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/neq.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Comparison;
+
+	/**
+	 * Creates a new inequality <code>Comparison</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function neq(a:*, b:*):Comparison
+	{
+		return Comparison.NotEqual(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/lte.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/lte.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/lte.as	(revision 15)
@@ -0,0 +1,20 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Comparison;
+
+	/**
+	 * Creates a new less-than-or-equal <code>Comparison</code> query
+	 * operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function lte(a:*, b:*):Comparison
+	{
+		return Comparison.LessThanOrEqual(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/max.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/max.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/max.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Maximum;
+	
+	/**
+	 * Creates a new <code>Maximum</code> query operator.
+	 * @param expr the input expression
+	 * @return the new query operator
+	 */
+	public function max(expr:*):Maximum
+	{
+		return new Maximum(expr);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/count.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/count.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/count.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Count;
+	
+	/**
+	 * Creates a new <code>Count</code> query operator.
+	 * @param expr the input expression
+	 * @return the new query operator
+	 */
+	public function count(expr:*):Count
+	{
+		return new Count(expr);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/stddev.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/stddev.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/stddev.as	(revision 15)
@@ -0,0 +1,15 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Variance;
+	
+	/**
+	 * Creates a new <code>Variance</code> query operator that computes
+	 * the population standard deviation.
+	 * @param expr the input expression
+	 * @return the new query operator
+	 */
+	public function stddev(expr:*):Variance
+	{
+		return new Variance(expr, Variance.DEVIATION);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/sub.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/sub.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/sub.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Arithmetic;
+
+	/**
+	 * Creates a new subtraction <code>Arithmetic</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function sub(a:*, b:*):Arithmetic
+	{
+		return Arithmetic.Subtract(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/range.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/range.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/range.as	(revision 15)
@@ -0,0 +1,22 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Range;
+	
+	/**
+	 * Creates a new <code>Range</code> query operator.
+	 * @param min the minimum range value.
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param max the maximum range value.
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param val the value to test for range inclusion.
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function range(min:*, max:*, val:*):Range
+	{
+		return new Range(min, max, val);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/mul.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/mul.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/mul.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Arithmetic;
+
+	/**
+	 * Creates a new multiplication <code>Arithmetic</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function mul(a:*, b:*):Arithmetic
+	{
+		return Arithmetic.Multiply(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/fn.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/fn.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/fn.as	(revision 15)
@@ -0,0 +1,18 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Fn;
+	
+	/**
+	 * Creates a new <code>Fn</code> query operator for a function in a query.
+	 * @param name the name of the function. This should be a function
+	 *  registered with the Fn class.
+	 * @param args a list of arguments to the function
+	 * @return the new Fn operator
+	 */
+	public function fn(name:String, ...args):Fn
+	{
+		var f:Fn = new Fn(name);
+		f.setChildren(args);
+		return f;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/orderby.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/orderby.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/orderby.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Query;
+	
+	/**
+	 * Create a new <code>Query</code> with the given sort criteria.
+	 * @param terms a list of sort criteria
+	 * @return the created query.
+	 */
+	public function orderby(...terms):Query
+	{
+		return new Query(null, null, terms);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/where.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/where.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/where.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Query;
+	
+	/**
+	 * Create a new <code>Query</code> with the given filter expression.
+	 * @param expr the filter expression
+	 * @return the created query.
+	 */
+	public function where(expr:*):Query
+	{
+		return new Query().where(expr);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/gt.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/gt.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/gt.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Comparison;
+
+	/**
+	 * Creates a new greater-than <code>Comparison</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function gt(a:*, b:*):Comparison
+	{
+		return Comparison.GreaterThan(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/isa.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/isa.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/isa.as	(revision 15)
@@ -0,0 +1,17 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.IsA;
+
+	/**
+	 * Creates a new <code>IsType</code> query operator.
+	 * @param type the class type to check for
+	 * @param x the expression to type check
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function isa(type:Class, x:*=null):IsA
+	{
+		return new IsA(type, x);
+	}	
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/_.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/_.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/_.as	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Literal;
+	
+	/**
+	 * Returns a new <code>Literal</code> operator.
+	 * @param the input object
+	 * @return the new Literal expression
+	 */
+	public function _(a:*):Literal
+	{
+		return new Literal(a);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/gte.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/gte.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/gte.as	(revision 15)
@@ -0,0 +1,20 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Comparison;
+
+	/**
+	 * Creates a new greater-than-or-equal <code>Comparison</code> query
+	 * operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function gte(a:*, b:*):Comparison
+	{
+		return Comparison.GreaterThanOrEqual(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/lt.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/lt.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/lt.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Comparison;
+
+	/**
+	 * Creates a new less-than <code>Comparison</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function lt(a:*, b:*):Comparison
+	{
+		return Comparison.LessThan(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/or.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/or.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/or.as	(revision 15)
@@ -0,0 +1,16 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Or;
+	
+	/**
+	 * Creates a new <code>Or</code> query operator.
+	 * @param rest a list of expressions to include in the or
+	 * @return the new query operator
+	 */
+	public function or(...rest):Or
+	{
+		var o:Or = new Or();
+		o.setChildren(rest);
+		return o;
+	}	
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/div.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/div.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/div.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Arithmetic;
+
+	/**
+	 * Creates a new division <code>Arithmetic</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function div(a:*, b:*):Arithmetic
+	{
+		return Arithmetic.Divide(a, b);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/variance.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/variance.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/variance.as	(revision 15)
@@ -0,0 +1,15 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Variance;
+	
+	/**
+	 * Creates a new <code>Variance</code> query operator that computes
+	 * the population variance.
+	 * @param expr the input expression
+	 * @return the new query operator
+	 */
+	public function variance(expr:*):Variance
+	{
+		return new Variance(expr);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/add.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/add.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/methods/add.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.flare.query.methods
+{
+	import gssim.gssimstudio.editor.flare.query.Arithmetic;
+
+	/**
+	 * Creates a new addition <code>Arithmetic</code> query operator.
+	 * @param a the left side argument. 
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @param b the right side argument
+	 *  This value can be an expression or a literal value.
+	 *  Literal values are parsed using the Expression.expr method.
+	 * @return the new query operator
+	 */
+	public function add(a:*, b:*):Arithmetic
+	{
+		return Arithmetic.Add(a, b);
+	}	
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/And.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/And.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/And.as	(revision 15)
@@ -0,0 +1,55 @@
+package gssim.gssimstudio.editor.flare.query
+{	
+	/**
+	 * Expression operator that computes the logical "and" of sub-expression
+	 * clauses.
+	 */
+	public class And extends CompositeExpression
+	{
+		/**
+		 * Creates a new And operator.
+		 * @param clauses the sub-expression clauses
+		 */
+		public function And(...clauses) {
+			super(clauses);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return cloneHelper(new And());
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return predicate(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function predicate(o:Object):Boolean
+		{
+			if (_children.length==0) return false;
+			
+			for each (var e:Expression in _children) {
+				if (!e.eval(o)) return false;
+			}
+			return true;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function toString():String
+		{
+			return _children.length==0 ? "FALSE" : super.getString("AND");
+		}
+		
+	} // end of class And
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Fn.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Fn.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Fn.as	(revision 15)
@@ -0,0 +1,125 @@
+package gssim.gssimstudio.editor.flare.query
+{	
+	/**
+	 * Expression operator that performs function invocation. The set of
+	 * available functions is determined by a static function table maintained
+	 * by this class. The function table can be extended to introduce custom
+	 * functions into the query language.
+	 */
+	public class Fn extends CompositeExpression
+	{
+		private var _name:String;
+		private var _func:Function;
+		private var _args:Array;
+		
+		/**
+		 * Creates a new Fn (function) operator.
+		 * @param name the name of the function. This should map to an entry
+		 *  in the static function table.
+		 * @params args sub-expressions for the function arguments
+		 */
+		public function Fn(name:String, ...args) {
+			_name = name.toUpperCase();
+			_func = table[_name];
+			super(args);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new Fn(_name, _children);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			// first, initialize the argument array as needed
+			if (_args == null || _args.length != _children.length) {
+				_args = new Array(_children.length);
+			}
+			// now evaluate all sub-expressions
+			for (var i:int=0; i<_children.length; ++i) {
+				_args[i] = _children[i].eval(o);
+			}
+			// now evaluate the function
+			return _func.apply(null, _args);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function toString():String
+		{
+			return _name + getString();
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/** 
+		 * Function table mapping function names to Function instances.
+		 * Functions can be added or removed at run-time by editing this
+		 * object.
+		 */
+		public static var table:Object = {
+			// Math Functions
+			ABS:		Math.abs,
+			ACOS:		Math.acos,
+			ASIN:		Math.asin,
+			ATAN:		Math.atan,
+			ATAN2:		Math.atan2,
+			CEIL:		Math.ceil,
+			CEILING:	Math.ceil,
+			COS:		Math.cos,
+			EXP:		Math.exp,
+			FLOOR:		Math.floor,
+			LOG:		Math.log,
+			MAX:		Math.max,
+			MIN:		Math.min,
+			POW:		Math.pow,
+			POWER:		Math.pow,
+			RANDOM:		Math.random,
+			ROUND:		Math.round,
+			SIN:		Math.sin,
+			SQRT:		Math.sqrt,
+			TAN:		Math.tan,
+			
+			// String Functions
+			CONCAT:		StringUtil.concat,
+			CONCAT_WS:	StringUtil.concat_ws,
+			FORMAT:		StringUtil.format,
+			INSERT:		StringUtil.insert,
+			LEFT:		StringUtil.left,
+			LENGTH:		StringUtil.length,
+			LOWER:		StringUtil.lower,
+			LCASE:		StringUtil.lower,
+			LPAD:		StringUtil.lpad,
+			MID:		StringUtil.substring,
+			POSITION:	StringUtil.position,
+			REVERSE:	StringUtil.reverse,
+			REPEAT:		StringUtil.repeat,
+			REPLACE:	StringUtil.replace,
+			RIGHT:		StringUtil.right,
+			RPAD:		StringUtil.rpad,
+			SPACE:		StringUtil.space,
+			SUBSTRING:	StringUtil.substring,
+			UPPER:		StringUtil.upper,
+			UCASE:		StringUtil.upper,
+			
+			// Date/Time Functions
+			DAY:		DateUtil.day,
+			DAYOFWEEK:	DateUtil.dayOfWeek,
+			HOUR:		DateUtil.hour,
+			MICROSECOND:DateUtil.microsecond,
+			MINUTE:		DateUtil.minute,
+			MONTH:		DateUtil.month,
+			NOW:		DateUtil.now,
+			SECOND:		DateUtil.second,
+			YEAR:		DateUtil.year
+		};
+		
+	} // end of class Fn
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Sum.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Sum.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Sum.as	(revision 15)
@@ -0,0 +1,46 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Aggregate operator for computing the sum of a set of values.
+	 */
+	public class Sum extends AggregateExpression
+	{
+		private var _sum:Number;
+		
+		/**
+		 * Creates a new Sum operator.
+		 * @param input the sub-expression of which to compute the sum
+		 */
+		public function Sum(input:*) {
+			super(input);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function reset():void
+		{
+			_sum = 0;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return _sum;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function aggregate(value:Object):void
+		{
+			var x:Number = Number(_expr.eval(value));
+			if (!isNaN(x)) {
+				_sum += x;
+			}
+		}
+		
+	} // end of class Sum
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/StringUtil.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/StringUtil.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/StringUtil.as	(revision 15)
@@ -0,0 +1,166 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	import flash.utils.ByteArray;
+	
+	/**
+	 * Utility class providing functions for manipulating <code>String</code>
+	 * objects. These functions are intended for use by the
+	 * <code>Fn</code> operator.
+	 */
+	public class StringUtil
+	{
+		public static function concat(...args):String
+		{
+			return args.join("");
+		}
+		
+		public static function concat_ws(sep:String, ...args):String
+		{
+			return args.join(sep);
+		}
+		
+		public static function format(x:Number, d:int):String
+		{
+			return x.toFixed(d);
+		}
+		
+		public static function insert(s:String, pos:int, len:int, ns:String):String
+		{
+			var slen:int = s.length;
+			if (pos < 0 || pos > slen)
+            	return s;
+	        if (len < 0 || len > slen)
+	            return s.substring(0,pos)+ns;
+	        else
+	            return s.substring(0,pos)+ns+s.substring(len);
+		}
+		
+		public static function left(s:String, len:int):String
+		{
+			return s.substring(0, len);
+		}
+		
+		public static function length(s:String):int
+		{
+			return s.length;
+		}
+		
+		public static function lower(s:String):String
+		{
+			return s.toLowerCase();
+		}
+		
+		public static function lpad(s:String, len:int, pad:String):String
+		{
+			var strlen:int = s.length;
+	        if (strlen > len) {
+	            return s.substring(0,len);
+	        }
+	        else if (strlen == len) {
+	            return s;
+	        }
+	        else {
+	        	var b:ByteArray = new ByteArray();
+	        	var padlen:int = pad.length;
+	        	var diff:int = len - strlen;
+
+	            for (var i:int=0; i<diff; i+=padlen)
+	            	b.writeUTFBytes(pad);
+	            if (b.length > diff)
+	            	b.position = diff;
+	            b.writeUTFBytes(s);
+	            b.position = 0;
+	            return b.readUTFBytes(b.length);
+	        }
+		}
+		
+		public static function position(sub:String, s:String):int
+		{
+			return s.indexOf(sub);
+		}
+		
+		public static function reverse(s:String):String
+		{
+			var b:ByteArray = new ByteArray();
+        	for (var i:int=s.length-1; --i>=0; ) {
+        		b.writeUTFBytes(s.charAt(i));
+        	}
+        	b.position = 0;
+        	return b.readUTFBytes(b.length);
+		}
+		
+		public static function repeat(s:String, count:int):String
+		{
+			var b:ByteArray = new ByteArray();
+        	for (var i:int=0; i<count; ++i) {
+        		b.writeUTFBytes(s);
+        	}
+        	b.position = 0;
+        	return b.readUTFBytes(b.length);
+		}
+		
+		public static function replace(s:String, orig:String, replace:String):String
+		{
+			return s.replace(new RegExp(orig, "g"), replace);
+		}
+		
+		public static function right(s:String, len:int):String
+		{
+			return s.substring(s.length-len);
+		}
+		
+		public static function rpad(s:String, len:int, pad:String):String
+		{
+			var strlen:int = s.length;
+	        if (strlen > len) {
+	            return s.substring(0,len);
+	        }
+	        else if (strlen == len) {
+	            return s;
+	        }
+	        else {
+	        	var b:ByteArray = new ByteArray();
+	        	b.writeUTFBytes(s);
+	        	var padlen:int = pad.length;
+	        	var diff:int = len - strlen;
+
+	            for (var i:int=0; i<diff; i+=padlen)
+	            	b.writeUTFBytes(pad);
+	            b.position = 0;
+	            return b.readUTFBytes(len);
+	        }
+		}
+		
+		public static function space(len:int):String
+		{
+			return repeat(" ", len);
+		}
+		
+		public static function substring(s:String, pos:int, len:int=-1):String
+		{
+			return len<0 ? s.substr(pos) : s.substr(pos, len);
+		}
+		
+		public static function upper(s:String):String
+		{
+			return s.toUpperCase();
+		}
+		
+		public static function startsWith(s:String, p:String):Boolean
+		{
+			return s.indexOf(p) == 0;
+		}
+		
+		public static function endsWith(s:String, p:String):Boolean
+		{
+			var diff:int = s.length - p.length;
+			if (diff < 0) return false;
+			for (var i:uint=0; i<p.length; ++i) {
+				if (s.charCodeAt(i+diff) != p.charCodeAt(i))
+					return false;
+			}
+			return true;
+		}
+
+	} // end of class StringUtil
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/BinaryExpression.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/BinaryExpression.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/BinaryExpression.as	(revision 15)
@@ -0,0 +1,102 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Base class for binary expression operators.
+	 */
+	public class BinaryExpression extends Expression
+	{
+		/** Code indicating the operation perfomed by this instance. */
+		protected var _op:int;
+		/** The left-hand-side sub-expression. */
+		protected var _left:Expression;
+		/** The right-hand-side sub-expression. */
+		protected var _right:Expression;
+		
+		/** Code indicating the operation performed by this instance. */
+		public function get operator():int { return _op; }
+		public function set operator(op:int):void { _op = op; }
+		/** String representation of the operation performed by this
+		 *  instance. */
+		public function get operatorString():String { return null; }
+		
+		/** The left-hand-side sub-expression. */
+		public function get left():Expression { return _left; }
+		public function set left(l:*):void {
+			_left = Expression.expr(l);
+		}
+		
+		/** The right-hand-side sub-expression. */
+		public function get right():Expression { return _right; }
+		public function set right(r:*):void {
+			_right = Expression.expr(r);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function get numChildren():int {
+			return 2;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new BinaryExpression.
+		 * @param op the operation code
+		 * @param minOp the minimum legal operation code
+		 * @param maxOp the maximum legal operation code
+		 * @param left the left-hand-side sub-expression
+		 * @param right the right-hand-side sub-expression
+		 */
+		public function BinaryExpression(op:int, minOp:int, maxOp:int,
+            left:*, right:*)
+	    {
+	        // operation check
+	        if (op < minOp || op > maxOp) {
+	            throw new ArgumentError("Unknown operation type: " + op);
+	        }
+	        // null check
+	        if (left == null || right == null) {
+	            throw new ArgumentError("Expressions must be non-null.");
+	        }
+	        _op = op;
+	        this.left = left;
+	        this.right = right;
+	    }
+	    
+	    /**
+		 * @inheritDoc
+		 */
+	    public override function getChildAt(idx:int):Expression
+	    {
+	    	switch (idx) {
+	    		case 0: return _left;
+	    		case 1: return _right;
+	    		default: return null;
+	    	}
+	    }
+	    
+	    /**
+		 * @inheritDoc
+		 */
+	    public override function setChildAt(idx:int, expr:Expression):Boolean
+	    {
+	    	switch (idx) {
+	    		case 0: _left = expr;  return true;
+	    		case 1: _right = expr; return true;
+	    		default: return false;
+	    	}
+	    }
+	    
+	    /**
+		 * @inheritDoc
+		 */
+	    public override function toString():String
+	    {
+	        return '(' + _left.toString() +' '
+	                   +  operatorString  +' '
+	        		   + _right.toString()+')';
+	    }
+
+	} // end of class BinaryExpression
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Query.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Query.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Query.as	(revision 15)
@@ -0,0 +1,434 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	import gssim.gssimstudio.editor.flare.util.Filter;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.Sort;
+	
+	/**
+	 * Performs query processing over a collection of ActionScript objects.
+	 * Queries can perform filtering, sorting, grouping, and aggregation
+	 * operations over a data collection. Arbitrary data collections can
+	 * be queried by providing a visitor function similar to the
+	 * <code>Array.forEach<code> method to the query <code>eval</code> method.
+	 * 
+	 * <p>The <code>select</code> and <code>where</code> methods in the
+	 * <code>flare.query.methods</code> package are useful shorthands
+	 * for helping to construct queries in code.</p>
+	 * 
+	 * <p>Here is an example of a query. It uses helper methods defined in the
+	 * <code>flare.query.methods</code> package. For example, the
+	 * <code>sum</code> method creates a <code>Sum</code> query operator and
+	 * the <code>_</code> method creates as a <code>Literal</code> expression
+	 * for its input value.</p>
+	 * 
+	 * <pre>
+	 * import gssim.gssimstudio.editor.flare.query.methods.*;
+	 * 
+	 * var data:Array = [
+	 *  {cat:"a", val:1}, {cat:"a", val:2}, {cat:"b", val:3}, {cat:"b", val:4},
+	 *  {cat:"c", val:5}, {cat:"c", val:6}, {cat:"d", val:7}, {cat:"d", val:8}
+	 * ];
+	 * 
+	 * var r:Array = select("cat", {sum:sum("val")}) // sum of values
+	 *               .where(neq("cat", _("d"))       // exclude category "d"
+	 *               .groupby("cat")                 // group by category
+	 *               .eval(data);                    // evaluate with data array
+	 * 
+	 * // r == [{cat:"a", sum:3}, {cat:"b", sum:7}, {cat:"c", sum:11}]
+	 * </pre>
+	 */
+	public class Query
+	{
+		private var _select:Array;
+		private var _orderby:Array;
+		private var _groupby:Array;
+		private var _where:Function;
+		private var _sort:Sort;
+		private var _aggrs:Array;
+		private var _map:Boolean = false;
+		private var _update:Boolean = false;
+		
+		/**
+		 * Creates a new Query.
+		 * @param select an array of select clauses. A select clause consists
+		 *  of either a string representing the name of a variable to query or
+		 *  an object of the form <code>{name:expr}</code>, where
+		 *  <code>name</code> is the name of the query variable to include in
+		 *  query result objects and <code>expr</code> is an Expression for
+		 *  the actual query value. Expressions can be any legal expression, 
+		 *  including aggregate operators.
+		 * @param where a where expression for filtering an object collection
+		 * @param orderby directives for sorting query results, using the
+		 *  format of the <code>flare.util.Sort</code> class methods.
+		 * @param groupby directives for grouping query results, using the
+		 *  format of the <code>flare.util.Sort</code> class methods.
+		 * @see flare.util.Sort
+		 */
+		public function Query(select:Array=null, where:*=null,
+							  orderby:Array=null, groupby:Array=null)
+		{
+			if (select != null) setSelect(select);
+			this.where(where);
+			_orderby = orderby;
+			_groupby = groupby;
+		}
+		
+		// -- public methods --------------------------------------------------
+		
+		/**
+		 * Sets the select clauses used by this query. A select clause consists
+		 * of either a string representing the name of a variable to query or
+		 * an object of the form <code>{name:expr}</code>, where
+		 * <code>name</code> is the name of the query variable to include in
+		 * query result objects and <code>expr</code> is an
+		 * <code>Expression</code> for the actual query value.
+		 * <p>Calling the <code>select</code> method will overwrite the effect
+		 * of any previous calls to the <code>select</code> or
+		 * <code>update</code> methods.</p>
+		 * @param terms a list of query terms (select clauses). If the first
+		 *  element is an array, it will be used as the term list.
+		 * @return this query object
+		 */
+		public function select(...terms):Query
+		{
+			if (terms.length > 0 && terms[0] is Array) {
+				terms = terms[0];
+			}
+			setSelect(terms);
+			_update = false;
+			return this;
+		}
+		
+		/**
+		 * Sets the select clauses used by this query to update the values
+		 * of the input set. An update clause consists of an object of the
+		 * form <code>{name:expr}</code>, where <code>name</code> is the name
+		 * of the data variable to set and <code>expr</code> is an
+		 * <code>Expression</code> for computing the value. When
+		 * <code>eval</code> is invoked for an update query, the values of the
+		 * input objects are updated and the returned result set is an array
+		 * containing these input objects.
+		 * <p>Calling the <code>update</code> method will overwrite the effect
+		 * of any previous calls to the <code>select</code> or
+		 * <code>update</code> methods.</p>
+		 * @param terms a list of query terms (update clauses). If the first
+		 *  element is an array, it will be used as the term list.
+		 * @return this query object
+		 */
+		public function update(...terms):Query
+		{
+			if (terms==null || terms.length==0) {
+				throw new Error("Nothing to update!");
+			} else if (terms[0] is Array) {
+				terms = terms[0];
+			}
+			setSelect(terms);
+			_update = true;
+			return this;
+		}
+		
+		/**
+		 * Sets the where clause (filter conditions) used by this query.
+		 * @param e the filter expression. This can be a string, a literal
+		 *  value, or an <code>Expression</code> instance. This input value
+		 *  will be run through the <code>Expression.expr</code> method.
+		 * @return this query object
+		 */
+		public function where(e:*):Query
+		{
+			_where = Filter.$(e);
+			return this;
+		}
+				
+		/**
+		 * Sets the sort order for query results.
+		 * @param terms the sort terms as a list of field names to sort on.
+		 *  By default, fields are sorted in ascending order. Add the prefix
+		 *  "-" (negative sign) to the field name to sort in descending order.
+		 * @return this query object
+		 */
+		public function orderby(...terms):Query
+		{
+			_orderby = (terms.length > 0 ? terms : null);
+			return this;
+		}
+		
+		/**
+		 * Sets the group by terms for aggregate queries.
+		 * @param terms an ordered list of terms to group by.
+		 * @return this query object
+		 */
+		public function groupby(...terms):Query
+		{
+			_groupby = (terms.length > 0 ? terms : null);
+			return this;
+		}
+		
+		/**
+		 * Sets whether or not aggregate functions will be mapped to all
+		 * tuples in the data set. This allows the results of aggregate
+		 * operators to be applied for all tuples. For example, the
+		 * <code>map</code> directive allows queries of this form:
+		 * <pre>
+		 * var q:Query = select({a:div(a,sum(a))}).map().eval(...);
+		 * </pre>
+		 * <p>The result include normalized <code>a</code> values for
+		 * all tuples in the input data. Without the map directive, a
+		 * "group-by" for all data would be assumed and only a single tuple
+		 * would be returned in the result set (matching the normal behavior
+		 * of a SQL database). Map can also be specified with a
+		 * group-by clause, in which case the aggregate operators will be
+		 * handled separately for each group, but the result set will still
+		 * contain a result for every tuple in the input set.</p>
+		 * <p>The map directive has no effect on "update" queries, which 
+		 * already apply map semantics. It only effects "select" queries.</p>
+		 * @param value if true (the default), aggregate operators will be
+		 *  applied (mapped) to all tuples; if false, normal group-by semantics
+		 *  will be used.
+		 * @return this query object
+		 */
+		public function map(value:Boolean=true):Query
+		{
+			_map = value;
+			return this;
+		}
+		
+		// -- helper methods --------------------------------------------------
+		
+		private function setSelect(a:Array):void {
+			_select = [];
+			for each (var o:Object in a) {
+				if (o is String) {
+					_select.push({
+						name: o as String,
+						expression: new Variable(o as String)
+					});
+				} else {
+					for (var n:String in o) {
+						_select.push({
+							name: n,
+							expression: Expression.expr(o[n])
+						});
+					}
+				}
+			}
+		}
+		
+		private function sorter():Sort
+		{
+			var s:Array = [], i:int;
+			if (_groupby != null) {
+				for (i=0; i<_groupby.length; ++i)
+					s.push(_groupby[i]);
+			}
+			if (_orderby != null) {
+				for (i=0; i<_orderby.length; ++i)
+					s.push(_orderby[i]);
+			}
+			return s.length==0 ? null : new Sort(s);
+		}
+		
+		private function aggregates():Array
+		{
+			var aggrs:Array = [];
+			for each (var pair:Object in _select) {
+				var expr:Expression = pair.expression;
+				expr.visit(function(e:Expression):void {
+					if (e is AggregateExpression)
+						aggrs.push(e);
+				});
+			}
+			return aggrs.length==0 ? null : aggrs;
+		}
+		
+		// -- query processing ------------------------------------------------
+		
+		/**
+		 * Evaluates this query on an object collection. The input argument can
+		 * either be an array of objects or a visitor function that takes 
+		 * another function as input and applies it to all items in a
+		 * collection.
+		 * @param input either an array of objects or a visitor function
+		 * @return an array of processed query results
+		 */
+		public function eval(input:*):Array
+		{
+			// check for initialization
+			if (_sort  == null) _sort  = sorter();
+			if (_aggrs == null) _aggrs = aggregates();
+			
+			// TODO -- evaluate any sub-queries in WHERE clause
+			var results:Array = [];
+			var visitor:Function;
+			if (input is Array) {
+				visitor = (input as Array).forEach;
+			} else if (input is Function) {
+				visitor = input as Function;
+			} else if (Object(input).hasOwnProperty("visit") &&
+					   Object(input).visit is Function) {
+				visitor = Object(input).visit as Function;
+			} else {
+				throw new ArgumentError("Illegal input argument: "+input);
+			}
+			
+			// collect and filter
+			if (_where != null) {
+				visitor(function(item:Object, ...rest):void {
+					if (_where(item)) results.push(item);
+				});
+			} else {
+				visitor(function(item:Object, ...rest):void {
+					results.push(item);
+				});
+			}
+			
+			// sort the result set
+			if (_sort != null) {
+				_sort.sort(results);
+			}
+			
+			if (_select == null) {
+				return results;
+			} else if (_update && _aggrs==null && _groupby==null) {
+				return applyAll(results);
+			} else if (_aggrs==null && _groupby==null) {
+				return projectAll(results);
+			} else {
+				return aggregate(results);
+			}
+		}
+		
+		private function projectAll(results:Array):Array
+		{					
+			for (var i:int=0; i<results.length; ++i) {
+				var item:Object = {};
+				for each (var pair:Object in _select) {
+					var p:Property = Property.$(pair.name);
+					var expr:Expression = pair.expression;
+					p.setValue(item, expr.eval(results[i]));
+				}
+				results[i] = item;
+			}
+			return results;
+		}
+		
+		private function applyAll(results:Array):Array
+		{
+			var o:Object = {};
+			for each (var item:Object in results) {
+				for each (var pair:Object in _select) {
+					var name:String = pair.name;
+					var expr:Expression = pair.expression;
+					o[name] = expr.eval(item);
+				}
+				for each (pair in _select) {
+					name = pair.name;
+					var p:Property = Property.$(name);
+					p.setValue(item, o[name]);
+				}
+			}
+			return results;
+		}
+		
+		// -- group-by and aggregation ----------------------------------------
+		
+		/**
+		 * Performs grouping and aggregation of query results.
+		 * @param items the filtered query results array
+		 * @return aggregated query results array
+		 */
+		private function aggregate(items:Array):Array
+		{
+			var h:int, i:int, j:int, item:Object;
+			var results:Array = [], props:Array = [];
+			
+			// get group-by properties as key
+			if (_groupby != null) {
+				for (i=_groupby.length; --i>=0;) {
+					if (_groupby[i] is String) {
+						props.push(Property.$(_groupby[i]));
+					}
+				}
+			}
+			
+			// process all groups
+			reset(_aggrs);
+			for (i=1, h=0, item=items[0]; i<=items.length; ++i) {
+				// update the aggregate functions
+				for each (var aggr:AggregateExpression in _aggrs) {
+					aggr.aggregate(items[i-1]);
+				}
+				// handle change of group
+				if (i==items.length || 
+					!(_groupby==null || sameGroup(props, item, items[i])))
+				{
+					if (_update) {
+						for (j=h; j<i; ++j)
+							apply(items[j]);
+					} else if (_map) {
+						for (j=h; j<i; ++j)
+							items[j] = project(items[j]);
+					} else {
+						results.push(project(item));
+					}
+					item = items[(h=i)];
+					reset(_aggrs);
+				}
+			}
+			
+			return (_update || _map ? items : results);
+		}
+		
+		private function reset(aggrs:Array):void
+		{
+			for each (var aggr:AggregateExpression in aggrs) {
+				aggr.reset();
+			}
+		}
+		
+		private function apply(item:Object):Object
+		{
+			var o:Object = {};
+			for each (var pair:Object in _select) {
+				var name:String = pair.name;
+				var expr:Expression = pair.expression;
+				o[name] = expr.eval(item);
+			}
+			for each (pair in _select) {
+				name = pair.name;
+				var p:Property = Property.$(name);
+				p.setValue(item, o[name]);
+			}
+			return item;
+		}
+		
+		private function project(item:Object):Object
+		{
+			var result:Object = {};
+			for each (var pair:Object in _select) {
+				var p:Property = Property.$(pair.name);
+				var expr:Expression = pair.expression;
+				p.setValue(result, expr.eval(item));
+			}
+			return result;
+		}
+		
+		private static function sameGroup(props:Array, x:Object, y:Object):Boolean
+		{
+			var a:*, b:*;
+			for each (var p:Property in props) {
+				a = p.getValue(x);
+				b = p.getValue(y);
+				
+				if (a is Date && b is Date) {
+					if ((a as Date).time != (b as Date).time)
+						return false;
+				} else if (a != b) {
+					return false;
+				}
+			}
+			return true;
+		}
+		
+	} // end of class Query
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/AggregateExpression.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/AggregateExpression.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/AggregateExpression.as	(revision 15)
@@ -0,0 +1,72 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Base class representing an aggregate query operator.
+	 */
+	public class AggregateExpression extends Expression
+	{
+		/** The sub-expression to aggregate. */
+		protected var _expr:Expression;
+		
+		/** The sub-expression to aggregate. */
+		public function get input():Expression { return _expr; }
+		public function set input(e:*):void {
+			_expr = Expression.expr(e);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function get numChildren():int {
+			return 1;
+		}
+		
+		/**
+		 * Creates a new AggregateExpression.
+		 * @param input the sub-expression to aggregate.
+		 */
+		public function AggregateExpression(input:*) {
+			this.input = input;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function getChildAt(idx:int):Expression
+	    {
+	    	return idx==0 ? _expr : null;
+	    }
+	    
+	    /**
+		 * @inheritDoc
+		 */
+	    public override function setChildAt(idx:int, expr:Expression):Boolean
+	    {
+	    	if (idx == 0) {
+	    		_expr = expr;
+	    		return true;
+	    	}
+	    	return false;
+	    }
+	    
+	    // --------------------------------------------------------------------
+	    
+	    /**
+	     * Resets the aggregation computation.
+	     */ 
+	    public function reset():void
+		{
+			// subclasses override this
+		}
+		
+		/**
+		 * Increments the aggregation computation to include the input value.
+		 * @param value a value to include within the aggregation.
+		 */
+		public function aggregate(value:Object):void
+		{
+			// subclasses override this
+		}
+	    
+	} // end of class AggregateExpression
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Xor.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Xor.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Xor.as	(revision 15)
@@ -0,0 +1,56 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Expression operator that computes the exclusive-or ("xor") of
+	 * sub-expression clauses.
+	 */
+	public class Xor extends CompositeExpression
+	{
+		/**
+		 * Creates a new Xor operator.
+		 * @param clauses the sub-expression clauses
+		 */
+		public function Xor(...clauses) {
+			super(clauses);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return cloneHelper(new Xor());
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return predicate(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function predicate(o:Object):Boolean
+		{
+			if (_children.length == 0) return false;
+			
+			var b:Boolean = _children[0].predicate(o);
+			for (var i:int=1; i<_children.length; ++i) {
+				b = (b != Expression(_children[i]).predicate(o));
+			}
+			return b;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function toString():String
+		{
+			return _children.length==0 ? "FALSE" : super.getString("XOR");
+		}
+		
+	} // end of class Xor
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/ExpressionIterator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/ExpressionIterator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/ExpressionIterator.as	(revision 15)
@@ -0,0 +1,131 @@
+package gssim.gssimstudio.editor.flare.query
+{	
+	/**
+	 * The ExpressionIterator simplifies the process of traversing an
+	 * expression tree.
+	 */
+	public class ExpressionIterator
+	{
+		private var _estack:Array;
+		private var _istack:Array;
+		private var _root:Expression;
+		private var _cur:Expression;
+		private var _idx:int;
+		
+		/** The expression being traversed. */
+		public function get expression():Expression { return _root; }
+		public function set expression(expr:Expression):void {
+			_root = expr; reset();
+		}
+		/** The parent expression of the iterator's current position. */
+		public function get parent():Expression { return _estack[_estack.length-1]; }
+		/** The expression at this iterator's current position. */
+		public function get current():Expression { return _cur; }
+		/** The depth of this iterator's current position in the
+		 *  expression tree. */
+		public function get depth():int { return _estack.length; }
+		/** An array of expressions from the root expression down to this
+		 *  iterator's current position. */
+		public function get path():Array {
+			var a:Array = new Array(_estack.length);
+			for (var i:int=0; i<a.length; ++i) { a[i] = _estack[i]; }
+			a.push(_cur);
+			return a;
+		}
+		
+		/**
+		 * Creates a new ExpressionIterator.
+		 * @param expr the expression to iterate over
+		 */
+		public function ExpressionIterator(expr:Expression=null) {
+			expression = expr;
+		}
+		
+		/**
+		 * Resets this iterator to the root of the expression tree.
+		 */
+		public function reset():void
+		{
+			_estack = new Array();
+			_istack = new Array();
+			_cur = _root;
+			_idx = 0;
+		}
+		
+		/**
+		 * Moves the iterator one level up the expression tree.
+		 * @return the new current expression, or null if the iterator
+		 *  could not move any further up the tree
+		 */
+		public function up():Expression
+		{
+			if (_cur != _root) {
+				_cur = _estack.pop();
+				_idx = _istack.pop();
+				return _cur;
+			} else {
+				return null;
+			}
+		}
+		
+		/**
+		 * Moves the iterator one level down the expression tree. By default,
+		 * the iterator moves to the left-most child of the previous position.
+		 * @param idx the index of the child expression this iterator should
+		 *  move down to
+		 * @return the new current expression, or null if the iterator
+		 *  could not move any further down the tree
+		 */
+		public function down(idx:int=0):Expression
+		{
+			if (idx >= 0 && _cur.numChildren > idx) {
+				_estack.push(_cur);
+				_istack.push(_idx);
+				_idx = idx;
+				_cur = _cur.getChildAt(_idx);
+				return _cur;
+			} else {
+				return null;
+			}
+		}
+		
+		/**
+		 * Moves the iterator to the next sibling expression in the expression
+		 * tree.
+		 * @return the new current expression, or null if the current position
+		 *  has no next sibling.
+		 */
+		public function next():Expression
+		{
+			if (_estack.length > 0) {
+				var p:Expression = _estack[_estack.length-1];
+				if (p.numChildren > _idx+1) {
+					_idx = _idx + 1;
+					_cur = p.getChildAt(_idx);
+					return _cur;
+				}
+			}
+			return null;
+		}
+		
+		/**
+		 * Moves the iterator to the previous sibling expression in the
+		 * expression tree.
+		 * @return the new current expression, or null if the current position
+		 *  has no previous sibling.
+		 */
+		public function prev():Expression
+		{
+			if (_estack.length > 0) {
+				var p:Expression = _estack[_estack.length-1];
+				if (_idx > 0) {
+					_idx = _idx - 1;
+					_cur = p.getChildAt(_idx);
+					return _cur;
+				}
+			}
+			return null;
+		}
+		
+	} // end of class ExpressionIterator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Comparison.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Comparison.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Comparison.as	(revision 15)
@@ -0,0 +1,167 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Expression operator for comparing sub-expression values. Performs
+	 * equals, not equals, less-than, greater-than, less-than-or-equal, or
+	 * greater-than-or-equal comparison.
+	 */
+	public class Comparison extends BinaryExpression
+	{
+		/** Indicates a less-than comparison. */
+	    public static const LT:int   = 0;
+    	/** Indicates a greater-than comparison. */
+    	public static const GT:int   = 1;
+    	/** Indicates a equals comparison. */
+    	public static const EQ:int   = 2;
+    	/** Indicates a not-equals comparison. */
+    	public static const NEQ:int  = 3;
+    	/** Indicates a less-than-or-equals comparison. */
+    	public static const LTEQ:int = 4;
+    	/** Indicates a greater-than-or-equals comparison. */
+    	public static const GTEQ:int = 5;
+
+		private var _cmp:Function = null;
+		
+		/** Comparison function for custom ordering criteria. */
+		public function get comparator():Function { return _cmp; }
+		public function set comparator(f:Function):void { _cmp = f; }
+		
+		/** Returns a string representation of the arithmetic operator. */
+		public override function get operatorString():String
+		{
+	        switch (_op) {
+	        	case LT:	return "<";
+	        	case GT:	return ">";
+	        	case EQ:	return "=";
+	        	case NEQ:	return "!=";
+	        	case LTEQ:	return "<=";
+	        	case GTEQ:	return ">=";
+	        	default: 	return "?";
+	        }
+	    }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new Comparison operator.
+		 * @param left the left-hand-side sub-expression to compare
+		 * @param right the right-hand-side sub-expression to compare
+		 * @param comparator a function to use for comparison (null by default)
+		 */
+		public function Comparison(op:int=2, left:*="",
+			right:*="", comparator:Function=null)
+		{
+			super(op, LT, GTEQ, left, right);
+			_cmp = comparator;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new Comparison(_op, _left.clone(), _right.clone(), _cmp);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return predicate(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function predicate(o:Object):Boolean
+		{
+			var l:Object = _left.eval(o);
+			var r:Object = _right.eval(o);
+			var c:int = (_cmp != null) ? _cmp(l, r) :
+				(l<r || r&&!1) ? -1 : (l>r || l&&!r) ? 1 : 0;
+			
+	        switch (_op) {
+	        	case LT:	return (c == -1);
+	        	case GT:	return (c == 1);
+	        	case EQ:	return (c == 0);
+	        	case NEQ:	return (c != 0);
+	        	case LTEQ:	return (c <= 0);
+	        	case GTEQ:	return (c >= 0);
+	        	default:
+	            	throw new Error("Unknown operation: "+_op);
+	        }
+		}
+
+		// -- Static Constructors ---------------------------------------------
+		
+		/**
+		 * Creates a new Comparison operator for a less-than comparison.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Comparison operator
+		 */
+		public static function LessThan(left:*, right:*):Comparison
+		{
+			return new Comparison(LT, left, right);
+		}
+		
+		/**
+		 * Creates a new Comparison operator for a greater-than comparison.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Comparison operator
+		 */
+		public static function GreaterThan(left:*, right:*):Comparison
+		{
+			return new Comparison(GT, left, right);
+		}
+		
+		/**
+		 * Creates a new Comparison operator for an equals comparison.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Comparison operator
+		 */
+		public static function Equal(left:*, right:*):Comparison
+		{
+			return new Comparison(EQ, left, right);
+		}
+		
+		/**
+		 * Creates a new Comparison operator for a not equals comparison.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Comparison operator
+		 */
+		public static function NotEqual(left:*, right:*):Comparison
+		{
+			return new Comparison(NEQ, left, right);
+		}
+		
+		/**
+		 * Creates a new Comparison operator for a less-than-or-equal
+		 * comparison.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Comparison operator
+		 */
+		public static function LessThanOrEqual(left:*, right:*):Comparison
+		{
+			return new Comparison(LTEQ, left, right);
+		}
+		
+		/**
+		 * Creates a new Comparison operator for a greater-than-or-equal
+		 * comparison.
+		 * @param left the left-hand input expression
+		 * @param right the right-hand input expression
+		 * @return the new Comparison operator
+		 */
+		public static function GreaterThanOrEqual(left:*, right:*):Comparison
+		{
+			return new Comparison(GTEQ, left, right);
+		}
+
+	} // end of class Comparison
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Average.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Average.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Average.as	(revision 15)
@@ -0,0 +1,49 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Aggregate operator for computing the average of a set of values.
+	 */
+	public class Average extends AggregateExpression
+	{
+		protected var _sum:Number;
+		protected var _count:Number;
+		
+		/**
+		 * Creates a new Average operator
+		 * @param input the sub-expression of which to compute the average
+		 */
+		public function Average(input:*) {
+			super(input);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function reset():void
+		{
+			_sum = 0;
+			_count = 0;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return _sum / _count;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function aggregate(value:Object):void
+		{
+			var x:Number = Number(_expr.eval(value));
+			if (!isNaN(x)) {
+				_sum += x;
+				_count += 1;
+			}
+		}
+		
+	} // end of class Average
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/DateUtil.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/DateUtil.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/DateUtil.as	(revision 15)
@@ -0,0 +1,124 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Utility class providing functions for manipulating <code>Date</code>
+	 * objects. These functions are intended for use by the
+	 * <code>Fn</code> operator.
+	 */
+	public class DateUtil
+	{
+
+// ADDDATE()(v4.1.1) 	Add dates
+// ADDTIME()(v4.1.1) 	Add time
+// CONVERT_TZ()(v4.1.3) 	Convert from one timezone to another
+// CURDATE() 	Return the current date
+// CURRENT_DATE(), CURRENT_DATE 	Synonyms for CURDATE()
+// CURRENT_TIME(), CURRENT_TIME 	Synonyms for CURTIME()
+// CURTIME() 	Return the current time
+// DATE_ADD() 	Add two dates
+// DATE_FORMAT() 	Format date as specified
+// DATE_SUB() 	Subtract two dates
+// DATE()(v4.1.1) 	Extract the date part of a date or datetime expression
+// DATEDIFF()(v4.1.1) 	Subtract two dates
+
+// DAYNAME()(v4.1.21) 	Return the name of the weekday
+
+		// DAYOFMONTH() 	Return the day of the month (1-31)
+		// DAY()(v4.1.1) 	Synonym for DAYOFMONTH()
+		public static function day(d:Date):int
+		{
+			return d.date;
+		}
+
+		// DAYOFWEEK() 	Return the weekday index of the argument
+		// WEEKDAY() 	Return the weekday index
+		public static function dayOfWeek(d:Date):int
+		{
+			return d.day;
+		}
+		
+// DAYOFYEAR() 	Return the day of the year (1-366)
+// EXTRACT 	Extract part of a date
+// FROM_DAYS() 	Convert a day number to a date
+// FROM_UNIXTIME() 	Format date as a UNIX timestamp
+// GET_FORMAT()(v4.1.1) 	Return a date format string
+
+		// HOUR() 	Extract the hour
+		public static function hour(d:Date):int
+		{
+			return d.hours;
+		}
+		
+// LAST_DAY(v4.1.1) 	Return the last day of the month for the argument
+// MAKEDATE()(v4.1.1) 	Create a date from the year and day of year
+// MAKETIME(v4.1.1) 	MAKETIME()
+
+		// MICROSECOND()(v4.1.1) 	Return the microseconds from argument
+		public static function microsecond(d:Date):int
+		{
+			return int(1000 * d.time) % 1000000;
+		}
+		
+		// MINUTE() 	Return the minute from the argument
+		public static function minute(d:Date):int
+		{
+			return d.minutes;
+		}
+		
+		// MONTH() 	Return the month from the date passed
+		public static function month(d:Date):int
+		{
+			return d.month;
+		}
+		
+// MONTHNAME()(v4.1.21) 	Return the name of the month
+
+		// NOW() 	Return the current date and time
+		// LOCALTIME(), LOCALTIME 	Synonym for NOW()
+		// LOCALTIMESTAMP, LOCALTIMESTAMP()(v4.0.6) 	Synonym for NOW()
+		// CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP 	Synonyms for NOW()
+		public static function now():Date
+		{
+			return new Date();
+		}
+
+// PERIOD_ADD() 	Add a period to a year-month
+// PERIOD_DIFF() 	Return the number of months between periods
+// QUARTER() 	Return the quarter from a date argument
+// SEC_TO_TIME() 	Converts seconds to 'HH:MM:SS' format
+
+		// SECOND() 	Return the second (0-59)
+		public static function second(d:Date):int
+		{
+			return d.seconds;
+		}
+
+// STR_TO_DATE()(v4.1.1) 	Convert a string to a date
+// SUBDATE() 	When invoked with three arguments a synonym for DATE_SUB()
+// SUBTIME()(v4.1.1) 	Subtract times
+// SYSDATE() 	Return the time at which the function executes
+// TIME_FORMAT() 	Format as time
+// TIME_TO_SEC() 	Return the argument converted to seconds
+// TIME()(v4.1.1) 	Extract the time portion of the expression passed
+// TIMEDIFF()(v4.1.1) 	Subtract time
+// TIMESTAMP()(v4.1.1) 	With a single argument, this function returns the date or datetime expression. With two arguments, the sum of the arguments
+// TIMESTAMPADD()(v5.0.0) 	Add an interval to a datetime expression
+// TIMESTAMPDIFF()(v5.0.0) 	Subtract an interval from a datetime expression
+// TO_DAYS() 	Return the date argument converted to days
+// UNIX_TIMESTAMP() 	Return a UNIX timestamp
+// TC_DATE()(v4.1.1) 	Return the current UTC date
+// UTC_TIME()(v4.1.1) 	Return the current UTC time
+// UTC_TIMESTAMP()(v4.1.1) 	Return the current UTC date and time
+// WEEK() 	Return the week number
+// WEEKOFYEAR()(v4.1.1) 	Return the calendar week of the date (1-53)
+
+		// YEAR() 	Return the year
+		public static function year(d:Date):int
+		{
+			return d.fullYear;
+		}
+		
+// YEARWEEK() 	Return the year and week
+
+	} // end of class DateUtil
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Minimum.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Minimum.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Minimum.as	(revision 15)
@@ -0,0 +1,46 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Aggregate operator for computing the minimum of a set of values.
+	 */
+	public class Minimum extends AggregateExpression
+	{
+		private var _value:Object = null;
+		
+		/**
+		 * Creates a new Minimum operator
+		 * @param input the sub-expression of which to compute the minimum
+		 */
+		public function Minimum(input:*) {
+			super(input);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return _value;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function reset():void
+		{
+			_value = null;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function aggregate(value:Object):void
+		{
+			value = _expr.eval(value);
+			if (_value == null || value < _value) {
+				_value = value;
+			}
+		}
+		
+	} // end of class Minimum
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/IsA.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/IsA.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/IsA.as	(revision 15)
@@ -0,0 +1,95 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Expression operator that type checks a sub-expression.
+	 */
+	public class IsA extends Expression
+	{
+		private var _type:Class;
+		private var _clause:Expression;
+		
+		/** The class type to check for. */
+		public function get type():Class { return _type; }
+		
+		/** The sub-expression clause to type check. */
+		public function get clause():Expression { return _clause; }
+		public function set clause(e:*):void {
+			_clause = e==null ? null : Expression.expr(e);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function get numChildren():int { return _clause ? 1 : 0; }
+		
+		/**
+		 * Creates a new IsA operator. 
+		 * @param type the class type to check for
+		 * @param clause the sub-expression clause to type check. If null,
+		 *  the input object (rather than a sub-property or expression result)
+		 *  will be type checked.
+		 */
+		public function IsA(type:Class, clause:*=null) {
+			_type = type;
+			this.clause = clause;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return new IsA(_type, _clause.clone());
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return predicate(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function predicate(o:Object):Boolean
+		{
+			if (_clause) {
+				return _clause.eval(o) is _type;
+			} else {
+				return o is _type;
+			}
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function getChildAt(idx:int):Expression
+		{
+			return (idx==0 ? _clause : null);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function setChildAt(idx:int, expr:Expression):Boolean
+		{
+			if (idx == 0) {
+				_clause = expr;
+				return true;
+			}
+			return false;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function toString():String
+		{
+			var c:String = _clause ? _clause.toString() : "<object>";
+			return "("+c + " IS " + _type.toString()+")";
+		}
+		
+	} // end of class IsA
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Maximum.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Maximum.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Maximum.as	(revision 15)
@@ -0,0 +1,46 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Aggregate operator for computing the maximum of a set of values.
+	 */
+	public class Maximum extends AggregateExpression
+	{
+		private var _value:Object = null;
+		
+		/**
+		 * Creates a new Maximum operator
+		 * @param input the sub-expression of which to compute the maximum
+		 */
+		public function Maximum(input:*) {
+			super(input);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return _value;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function reset():void
+		{
+			_value = null;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function aggregate(value:Object):void
+		{
+			value = _expr.eval(value);
+			if (_value == null || value > _value) {
+				_value = value;
+			}
+		}
+		
+	} // end of class Maximum
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Or.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Or.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Or.as	(revision 15)
@@ -0,0 +1,53 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Expression operator that computes the logical "or" of sub-expression
+	 * clauses.
+	 */
+	public class Or extends CompositeExpression
+	{
+		/**
+		 * Creates a new Or operator.
+		 * @param clauses the sub-expression clauses
+		 */
+		public function Or(...clauses) {
+			super(clauses);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function clone():Expression
+		{
+			return cloneHelper(new Or());
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return predicate(o);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function predicate(o:Object):Boolean
+		{
+			for each (var e:Expression in _children) {
+				if (e.eval(o)) return true;
+			}
+			return false;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function toString():String
+		{
+			return _children.length==0 ? "FALSE" : super.getString("OR");
+		}
+		
+	} // end of class Or
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Distinct.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Distinct.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/Distinct.as	(revision 15)
@@ -0,0 +1,51 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	/**
+	 * Aggregate (group-by) operator for counting the number of distinct
+	 * values in a set of values.
+	 */
+	public class Distinct extends AggregateExpression
+	{
+		private var _map:Object;
+		private var _count:int;
+		
+		/**
+		 * Creates a new Distinct operator
+		 * @param input the sub-expression of which to compute the distinct
+		 *  values
+		 */
+		public function Distinct(input:*) {
+			super(input);
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function reset():void
+		{
+			_map = {};
+			_count = 0;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function eval(o:Object=null):*
+		{
+			return _count;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function aggregate(value:Object):void
+		{
+			value = _expr.eval(value);
+			if (_map[value] == undefined) {
+				_count++;
+				_map[value] = 1;
+			}
+		}
+		
+	} // end of class Distinct
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/CompositeExpression.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/CompositeExpression.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/query/CompositeExpression.as	(revision 15)
@@ -0,0 +1,148 @@
+package gssim.gssimstudio.editor.flare.query
+{
+	import flash.utils.ByteArray;
+	
+	/**
+	 * Base class for expressions with an arbitrary number of sub-expressions.
+	 */
+	public class CompositeExpression extends Expression
+	{
+		/** Array of sub-expressions. */
+		protected var _children:Array;
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function get numChildren():int {
+			return _children.length;
+		}
+		
+		/**
+		 * Creates a new CompositeExpression.
+		 * @param items either a single sub-expression or an array of
+		 *  sub-expressions
+		 */
+		public function CompositeExpression(items:Object=null) {
+			if (items is Array) {
+				setChildren(items as Array);
+			} else if (items is Expression) {
+				_children = new Array();
+				addChild(items as Expression);
+			} else if (items == null) {
+				_children = new Array();
+			} else {
+				throw new ArgumentError(
+					"Input must be an expression or array of expressions");
+			}
+		}
+		
+		/**
+		 * Helper routine that clones this composite's sub-expressions.
+		 * @param ce the cloned composite expression
+		 * @return the input expression
+		 */
+		protected function cloneHelper(ce:CompositeExpression):Expression
+		{
+			for (var i:int=0; i<_children.length; ++i) {
+				ce.addChild(Expression(_children[i]).clone());
+			}
+			return ce;
+		}
+		
+		/**
+		 * Sets the sub-expressions of this composite
+		 * @param array an array of sub-expressions
+		 */
+		public function setChildren(array:Array):void
+		{
+			_children = new Array();
+			for each (var e:* in array) {
+				_children.push(Expression.expr(e));
+			}
+		}
+		
+		/**
+		 * Adds an additional sub-expression to this composite.
+		 * @param expr the sub-expression to add.
+		 */
+		public function addChild(expr:Expression):void
+		{
+			_children.push(expr);
+		}
+		
+		/**
+		 * Removes a sub-expression from this composite.
+		 * @param expr the sub-epxressions to remove
+		 * @return true if the expression was found and removed, false
+		 *  otherwise
+		 */
+		public function removeChild(expr:Expression):Boolean
+		{
+			var idx:int = _children.indexOf(expr);
+			if (idx >= 0) {
+				_children.splice(idx, 1);
+				return true;
+			} else {
+				return false;
+			}
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function getChildAt(idx:int):Expression
+		{
+			return _children[idx];
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public override function setChildAt(idx:int, expr:Expression):Boolean
+		{
+			if (idx>=0 && idx<_children.length) {
+				_children[idx] = expr;
+				return true;
+			}
+			return false;
+		}
+		
+		/**
+		 * Removes all sub-expressions from this composite.
+		 */
+		public function removeAllChildren():void
+		{
+			while (_children.length > 0) _children.pop();
+		}
+		
+		/**
+		 * Returns a string representation of this composite's sub-expressions.
+		 * @param op a string describing the sub-class operator (null by
+		 *  default). If non-null, the operator string will be interspersed
+		 *  between sub-expression values in the output string.
+		 * @return the requested string
+		 */
+		protected function getString(op:String=null):String
+		{	        
+	        var b:ByteArray = new ByteArray();
+	        b.writeUTFBytes('(');
+			for (var i:uint=0; i<_children.length; ++i) {
+				if (i > 0) {
+					if (op == null) {
+						b.writeUTFBytes(', ');
+					} else {
+						b.writeUTFBytes(' ');
+						b.writeUTFBytes(op);
+						b.writeUTFBytes(' ');
+					}
+				}
+				b.writeUTFBytes(_children[i].toString());
+			}
+			b.writeUTFBytes(')');	        
+
+			b.position = 0;
+	        return b.readUTFBytes(b.length);
+		}
+		
+	} // end of class CompositeExpression
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/HierarchicalCluster.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/HierarchicalCluster.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/HierarchicalCluster.as	(revision 15)
@@ -0,0 +1,195 @@
+package gssim.gssimstudio.editor.flare.analytics.cluster
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.Sort;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.Tree;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+
+	/**
+	 * Base class for clustering operators that construct a hierarchical
+	 * clustering tree. Provides methods for taking a sequence of
+	 * merge operations by a clustering algorithm and constructing a
+	 * resulting cluster tree.
+	 * 
+	 * <p>Once a clustering has been computed, each node included in the
+	 * analysis will be annotated with both its cluster membership
+	 * using the name indicated by the <code>clusterField</code> property.
+	 * By default, this class will attempt to pick an optimal level of the
+	 * cluster tree at which to break up items into discrete clusters.
+	 * However, clients can invoke the <code>labelNodes</code> method with
+	 * a specific merge number which indicates the point at which to "cut"
+	 * the cluster tree into discrete sub-clusters. This class also annotates
+	 * nodes with a sequence number using the name indicated by the
+	 * <code>sequenceField</code> property. The sequence number allows items
+	 * to be sorted in a way that attempts to preserve the clustered structure.
+	 * Additionally, the <code>clusterTree</code> property will return a
+	 * <code>flare.vis.data.Tree</code> instance that can be used to
+	 * visualize the structure of the cluster tree.</p>
+	 */
+	public class HierarchicalCluster extends Operator
+	{
+		/** @private */
+		protected var _idx:Property = Property.$("props.sequence");
+		/** @private */
+		protected var _com:Property = Property.$("props.cluster");
+		
+		/** @private */
+		protected var _qvals:Array;
+		/** @private */
+		protected var _merges:MergeEdge;
+		/** @private */
+		protected var _size:int;
+		/** @private */
+		protected var _tree:Tree;
+		/** @private */
+		protected var _group:String = Data.NODES;
+		
+		/** The data group to cluster. */
+		public function get group():String { return _group; }
+		public function set group(g:String):void { _group = g; }
+		
+		/** The property in which to store cluster indices. This property
+		 *  is used to annotate nodes with the community they belong to
+		 *  (indicated as an integer index). The default value
+		 *  is "props.cluster". */
+		public function get clusterField():String { return _com.name; }
+		public function set clusterField(f:String):void { _com = Property.$(f); }
+		
+		/** The property in which to store sequence indices. This property
+		 *  is used to annotate nodes with their sequence index along the
+		 *  computed cluster tree. This value can be used to sort the nodes
+		 *  in a way that best preserves community structure. The default value
+		 *  is "props.sequence". */
+		public function get sequenceField():String { return _idx.name; }
+		public function set sequenceField(f:String):void { _idx = Property.$(f); }
+		
+		/** Computed criterion values for each merge in the cluster tree. */
+		public function get criteria():Array { return _qvals; }
+		
+		/** The cluster tree of detected community structures. The leaf nodes
+		 *  correspond to each of the nodes in the input graph, and include the
+		 *  same <code>data</code> property. Non-leaf nodes indicate merges
+		 *  made by the clustering algorithm, and have <code>data</code>
+		 *  properties that include the <code>merge</code> number (1 for the
+		 *  first merger, 2 for the second, etc), the <code>criterion</code>
+		 *  value computed for that merge, and the <code>size</code> of the
+		 *  cluster rooted at that node (the number of descendants in the
+		 *  cluster tree).
+		 */
+		public function get clusterTree():Tree { return _tree; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new HierarchicalCluster instance. 
+		 */
+		public function HierarchicalCluster()
+		{
+			super();
+		}
+		
+		/**
+		 * Labels nodes with their cluster membership, determined by
+		 * the given merge number. If the merge number is less than
+		 * zero or unprovided, the merge number that maximizes the
+		 * clustering criteria will be assumed.
+		 * @param merge the merge number at which to compute the clusters
+		 */
+		public function labelNodes(merge:int=-1):void
+		{
+			if (merge < 0) merge = Arrays.maxIndex(_qvals);
+			var com:int, idx:int;
+			var helper:Function = function(n:NodeSprite):void
+			{
+				var nn:NodeSprite;
+				if (n.childDegree && n.data.merge > merge)
+				{
+					for (var i:int=0; i<n.childDegree; ++i)
+						helper(n.getChildNode(i));
+				}
+				else if (n.childDegree)
+				{
+					n.visitTreeDepthFirst(function(c:NodeSprite):void {
+						if (c.childDegree==0) {
+							nn = c.props.node;
+							_com.setValue(nn, com);
+							_idx.setValue(nn, idx++);
+						}
+					});
+					com++;
+				}
+				else
+				{
+					nn = n.props.node;
+					_com.setValue(nn, com++);
+					_idx.setValue(nn, idx++);
+				}
+			}
+			helper(_tree.root);
+		}
+		
+		/**
+		 * @private
+		 * Constructs the cluster tree from the cluster results
+		 */
+		protected function buildTree(list:DataList):Tree
+		{
+			var tree:Tree = new Tree();
+			
+			var e:MergeEdge, i:int, j:int, ii:int, map:Object = {};
+			var l:NodeSprite, r:NodeSprite, p:NodeSprite;
+			
+			// populate the leaf notes
+			for (i=0; i<_size; ++i) {
+				map[i] = (p = new NodeSprite());
+				p.data = list[i].data;
+				p.props.node = list[i];
+				p.props.size = 0;
+			}
+			
+			// build up the tree
+			for (ii=0, e=_merges.next; e!=null; ++ii, e=e.next) {
+				i = e.i;
+				j = e.j;
+				l = map[i];
+				r = map[j];
+				map[i] = (p = new NodeSprite());
+				if (l.props.size >= r.props.size) {
+					p.addChildEdge(new EdgeSprite(p, l));
+					p.addChildEdge(new EdgeSprite(p, r));
+				} else {
+					p.addChildEdge(new EdgeSprite(p, r));
+					p.addChildEdge(new EdgeSprite(p, l));
+				}
+				p.data.merge = ii + 1;
+				p.data.criterion = _qvals[ii];
+				p.props.size = 2 + l.props.size + r.props.size;
+				delete map[j];
+			}
+			
+			// build and sort array of cluster roots
+			var roots:Array = [];
+			for each (var n:NodeSprite in map) roots.push(n);
+			roots.sort(Sort.$("-props.size"));
+			
+			// merge cluster roots into final tree, if needed
+			if (roots.length == 1) {
+				p = NodeSprite(roots[0]);
+			} else {
+				p = new NodeSprite();
+				p.data.merge = ii;
+				for each (n in roots) {
+					p.addChildEdge(new EdgeSprite(p, n));
+				}
+			}
+			tree.root = p;
+			return tree;
+		}
+		
+	} // end of class HierarchicalCluster
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/MergeEdge.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/MergeEdge.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/MergeEdge.as	(revision 15)
@@ -0,0 +1,40 @@
+package gssim.gssimstudio.editor.flare.analytics.cluster
+{
+	/**
+	 * Auxiliary class that represents a merge in a clustering.
+	 */
+	internal class MergeEdge
+	{
+		public var i:int;
+		public var j:int;
+		public var next:MergeEdge = null;
+		public var prev:MergeEdge = null;
+		
+		public function MergeEdge(i:int, j:int) {
+			this.i = i;
+			this.j = j;
+		}
+		
+		public function update(i:int, j:int):void
+		{
+			this.i = i;
+			this.j = j;
+		}
+		
+		public function add(e:MergeEdge):MergeEdge {
+			if (next) {
+				e.next = next;
+				next.prev = e;
+			}
+			next = e;
+			e.prev = this;
+			return e;
+		}
+		
+		public function remove():void {
+			if (prev) prev.next = next;
+			if (next) next.prev = prev;
+		}
+		
+	} // end of class MergeEdge
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/CommunityStructure.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/CommunityStructure.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/CommunityStructure.as	(revision 15)
@@ -0,0 +1,134 @@
+package gssim.gssimstudio.editor.flare.analytics.cluster
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.math.IMatrix;
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	
+	/**
+	 * Hierarchically clusters a network based on inferred community structure.
+	 * The result is a cluster tree in which each merge is chosen so as to
+	 * maximize within-cluster linkage while minimizing between-cluster linkage.
+	 * This class uses <a href="http://arxiv.org/abs/cond-mat/0309508">Newman's
+	 * fast algorithm for detecting community structure</a>. Optionally allows
+	 * clients to provide an edge weight function indicating the strength of
+	 * ties within the network.
+	 */
+	public class CommunityStructure extends HierarchicalCluster
+	{
+		/** A function defining edge weights in the graph. */
+		public var edgeWeights:Function = null;
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new community structure instance
+		 */
+		public function CommunityStructure()
+		{
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			calculate(visualization.data.group(group), edgeWeights);
+		}
+		
+		/**
+		 * Calculates the community structure clustering. As a result of this
+		 * method, a cluster tree will be computed and graph nodes will be
+		 * annotated with both community and sequence indices.
+		 * @param list the data list to cluster
+		 * @param w an edge weighting function. If null, each edge will be
+		 *  given weight one.
+		 */
+		public function calculate(list:DataList, w:Function=null):void
+		{
+			compute(list.adjacencyMatrix(w));
+			_tree = buildTree(list);
+			labelNodes();
+		}
+		
+		/** Computes the clustering */
+		private function compute(G:IMatrix):void
+		{
+			_merges = new MergeEdge(-1, -1); _qvals = [];
+			_size = G.rows;
+			var i:int, j:int, k:int, s:int, t:int, v:Number;
+			var Q:Number=0, Qmax:Number=0, dQ:Number, dQmax:Number=0, imax:int;
+			
+			// initialize normalized matrix
+			var N:int = G.rows, Z:IMatrix = G.clone();
+			for (i=0; i<N; ++i) Z.set(i,i,0); // clear diagonal
+			Z.scale(1 / Z.sum); // normalize matrix
+			
+			// initialize column sums and edge list
+			var E:MergeEdge = new MergeEdge(-1,-1);
+			var e:MergeEdge = E, m:MergeEdge = _merges;
+			var eMax:MergeEdge = new MergeEdge(0,0);
+			var A:Array = new Array(N);
+			
+			for (i=0; i<N; ++i) {
+				A[i] = 0;
+				for (j=0; j<N; ++j) {
+					if ((v=Z.get(i,j)) != 0) {
+						A[i] += v;
+						e = e.add(new MergeEdge(i,j));
+					}
+				}
+			}
+			
+			// run the clustering algorithm
+			for (var ii:int=0; ii<N-1 && E.next; ++ii) {
+				dQmax = Number.NEGATIVE_INFINITY;
+				eMax.update(0,0);
+				
+				// find the edge to merge
+				for (e=E.next; e!=null; e=e.next) {
+					i = e.i; j = e.j;
+					if (i==j) continue;
+					dQ = Z.get(i,j) + Z.get(j,i) - 2*A[i]*A[j];
+					if (dQ > dQmax) {
+						dQmax = dQ; eMax.update(i,j);
+					}
+				}
+				
+				// perform merge on graph
+				i = eMax.i; j = eMax.j; if (j<i) { i=eMax.j; j=eMax.i; }
+				var na:Number = 0;
+				for (k=0; k<N; ++k) {
+					v = Z.get(i,k) + Z.get(j,k);
+					if (v != 0) {
+						na += v; Z.set(i,k,v); Z.set(j,k,0);
+					}
+				}
+				for (k=0; k<N; ++k) {
+					v = Z.get(k,i) + Z.get(k,j);
+					if (v != 0) {
+						Z.set(k,i,v); Z.set(k,j,0);
+					}
+				}
+				A[i] = na;
+				A[j] = 0;
+				for (e=E.next; e!=null; e=e.next) {
+					s = e.i; t = e.j;
+					if ((i==s && j==t) || (i==t && j==s)) {
+						e.remove();
+					} else if (s==j) {
+						e.i = i;
+					} else if (t==j) {
+						e.j = i;
+					}
+				}
+				
+				Q += dQmax;
+				if (Q > Qmax) {
+					Qmax = Q;
+					imax = ii;
+				}
+				_qvals.push(Q);
+				m = m.add(new MergeEdge(i,j));
+			}
+		}
+		
+	} // end of class CommunityStructure
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/AgglomerativeCluster.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/AgglomerativeCluster.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/cluster/AgglomerativeCluster.as	(revision 15)
@@ -0,0 +1,129 @@
+package gssim.gssimstudio.editor.flare.analytics.cluster
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.math.IMatrix;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	
+	/**
+	 * Hierarchically clusters a set of items using agglomerative clustering.
+	 * This approach continually merges the most similar items (those with the
+	 * minimum distance between them) into clusters, until all items have been
+	 * merged into a final resulting cluster tree. Clients must provide a
+	 * distance function that takes as input two <code>DataSprite</code>
+	 * instances and returns a <code>Number</code>.
+	 * <p>This class supports both <i>minimum-link</i> clustering, in which the
+	 * distance between clusters is measured as the distance between the two
+	 * nearest items in each cluster, and <i>maximum-link</i> clustering, in
+	 * which distance is measured using the two furthest items in each cluster.
+	 * </p>
+	 * <p>For a richer description, see
+	 * <a href="http://en.wikipedia.org/wiki/Cluster_analysis#Agglomerative_hierarchical_clustering">
+	 * the Wikipedia article on Cluster Analysis</a>.
+	 * </p>
+	 */
+	public class AgglomerativeCluster extends HierarchicalCluster
+	{		
+		/** A function defining distances between items. */
+		public var distance:Function = null;
+		
+		/** If true, minimum-link distances are computed between clusters.
+		 *  If false, maximum-link distances are computed between clusters. */
+		public var minLink:Boolean = true;
+
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new agglomerative cluster instance
+		 */
+		public function AgglomerativeCluster(group:String=Data.NODES)
+		{
+			this.group = group;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			calculate(visualization.data.group(group), distance);
+		}
+		
+		/**
+		 * Calculates the community structure clustering. As a result of this
+		 * method, a cluster tree will be computed and graph nodes will be
+		 * annotated with both community and sequence indices.
+		 * @param list a data list to cluster
+		 * @param d a distance function
+		 */
+		public function calculate(list:DataList, d:Function):void
+		{
+			compute(list.distanceMatrix(d));
+			_tree = buildTree(list);
+			labelNodes();
+		}
+		
+		/** Computes the clustering */
+		private function compute(Z:IMatrix):void
+		{
+			_merges = new MergeEdge(-1, -1);
+			_qvals = [];
+			_size = Z.rows;
+			
+			var m:MergeEdge = _merges;
+			var i:uint, j:uint, k:int, s:int, t:int, ii:uint, jj:uint;
+			var min:Number, a:uint, b:uint, bb:uint, imax:int;
+			var v:Number, sum:Number=0, Q:Number=0, Qmax:Number=0, dQ:Number;
+			
+			// initialize matrix
+			var N:int = Z.rows;
+			var idx:/*int*/Array = new Array(N);
+			for (i=0; i<N; ++i) {
+				idx[i] = i;
+				Z.set(i,i,Number.POSITIVE_INFINITY);
+			}
+			
+			// run the clustering algorithm
+			for (var iter:int=0; iter<N-1; ++iter) {
+				// find the nodes to merge
+				min = Number.MAX_VALUE;
+				for (ii=0; ii<idx.length; ++ii) {
+					i = idx[ii];
+					for (jj=ii+1; jj<idx.length; ++jj) {
+						j = idx[jj];
+						v = Z.get(i,j);
+						if (v < min) {
+							min = v;
+							a = i;
+							b = j; bb = jj;
+						}
+					}
+				}
+				i = a; j = b; jj = bb;
+				
+				// perform merge on graph
+				for (k=0; k<N; ++k) {
+					if (minLink) {
+						v = Math.min(Z.get(i,k), Z.get(j,k)); // min link
+					} else {
+						v = Math.max(Z.get(i,k), Z.get(j,k)); // max link
+					}
+					Z.set(i, k, v);
+					Z.set(k, i, v);
+				}
+				for (k=0; k<N; ++k) {
+					Z.set(j, k, Number.POSITIVE_INFINITY);
+					Z.set(k, j, Number.POSITIVE_INFINITY);
+				}
+				idx.splice(jj, 1);
+				
+				Q += min;
+				if (Q > Qmax) {
+					Qmax = Q;
+					imax = iter;
+				}
+				_qvals.push(Q);
+				m = m.add(new MergeEdge(i,j));
+			}
+		}
+		
+	} // end of class AgglomerativeCluster
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/LinkDistance.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/LinkDistance.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/LinkDistance.as	(revision 15)
@@ -0,0 +1,151 @@
+package gssim.gssimstudio.editor.flare.analytics.graph
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+	
+	/**
+	 * Calculates the link distance from a source node based on a breadth-first
+	 * traversal. Link distance is calculated as the smallest number of edges
+	 * connecting a node to a source node. Any edge weights are ignored, to
+	 * include weighted edges in the calculation, use the
+	 * <code>ShortestPaths</code> operator instead.
+	 * 
+	 * </p>Nodes are annotated with both the computed distance and the incoming
+	 * edge in the shortest link distance path to a source node. Edges are
+	 * annotated with a Boolean value indicating whether or not the edge lies
+	 * along one of these computed shortest paths.</p>
+	 */
+	public class LinkDistance extends Operator
+	{
+		private var _d:Property = Property.$("props.distance");
+		private var _p:Property = Property.$("props.incoming");
+		private var _e:Property = Property.$("props.onpath");
+		private var _links:int = NodeSprite.GRAPH_LINKS;
+		
+		/** The roots of the breadth-first search. The elements of the array
+		 *  should either be NodeSprite instances or integer indices into
+		 *  the node array. */
+		public var sources:Array;
+		
+		/** The property in which to store the link distance. This property
+		 *  is used to annotate nodes with the minimum link distance to one of
+		 *  the source nodes. The default value is "props.distance". */
+		public function get distanceField():String { return _d.name; }
+		public function set distanceField(f:String):void { _d = Property.$(f); }
+		
+		/** The property in which to store incoming edges along a shortest
+		 *  path. This property is used to annotate nodes with the incoming
+		 *  along a shortest path from one of the source nodes. By following
+		 *  sequential incoming edges, one can recreate the shortest path from
+		 *  the nearest source node. The default value is "props.incoming". */
+		public function get incomingField():String { return _p.name; }
+		public function set incomingField(f:String):void { _p = Property.$(f); }
+		
+		/** The property in which to store a path inclusion flag for edges.
+		 *  This property is used to mark edges as belonging to one of the
+		 *  computed shortest paths: <code>true</code> indicates that the edge
+		 *  participates in a shortest path, <code>false</code> indicates that
+		 *  the edge does not lie along a shortest path. The default value is
+		 *  "props.onpath". */
+		public function get onpathField():String { return _p.name; }
+		public function set onpathField(f:String):void { _p = Property.$(f); }
+		
+		/** The link type to consider when calculating link distance. Should
+		 *  be one of <code>NodeSprite.GRAPH_LINKS</code>,
+		 *  <code>NodeSprite.IN_LINKS</code>, or
+		 *  <code>NodeSprite.OUT_LINKS</code>. */
+		public function get links():int { return _links; }
+		public function set links(linkType:int):void {
+			if (linkType == NodeSprite.GRAPH_LINKS ||
+				linkType == NodeSprite.IN_LINKS ||
+				linkType == NodeSprite.OUT_LINKS) 
+			{
+				_links = linkType;
+			} else {
+				throw new Error("Unsupported link type: "+linkType);
+			}
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new LinkDistance operator.
+		 * @param sources an Array specifying the roots of the breadth-first
+		 *  search. The elements of the array should either be
+		 *  <code>NodeSprite</code> instances or integer indices into the node
+		 *  array.
+		 */
+		public function LinkDistance(sources:Array=null)
+		{
+			this.sources = sources;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			calculate(visualization.data, sources);
+		}
+			
+		/**
+		 * Calculates link distances from a set of source nodes for for each
+		 * node in the graph. Each node in the graph will be annotated with
+		 * its link distance from the nearest source node.
+		 * @param data the graph to calculate distances for
+		 * @param sources one or more source nodes from which to measure the
+		 *  distance. This input can either be a single node or an array of
+		 *  nodes. Nodes can be indicated as either a <code>NodeSprite</code>
+		 *  instance or an integer index into the <code>data.nodes</code>
+		 *  property.
+		 */
+		public function calculate(data:Data, sources:*):void
+		{
+			var i:int, n:NodeSprite;
+			data.edges.setProperty(_e.name, false);
+			data.nodes.visit(function(n:NodeSprite):void {
+				_d.setValue(n, Number.POSITIVE_INFINITY);
+				_p.setValue(n, null);
+			});
+						
+			// initialize queue
+			var roots:Array = sources is Array ? sources as Array : [sources];
+			var queue:Array = [];
+			for (i=0; i<roots.length; ++i) {
+				var r:Object = roots[i];
+				if (r is NodeSprite) {
+					n = NodeSprite(r);
+				} else if (r is int) {
+					n = data.nodes[int(r)];
+				}
+				queue.push(n);
+				_d.setValue(n, 0);
+			}
+			
+			while (queue.length > 0) {
+				var u:NodeSprite = queue.shift();
+				var du:int = _d.getValue(u) + 1;
+				u.visitEdges(function(e:EdgeSprite):void {
+					var v:NodeSprite = e.other(u);
+					var d:Number = _d.getValue(v);
+					if (!isFinite(d)) {
+						queue.push(v);
+						_d.setValue(v, du); 
+						_p.setValue(v, e);
+					} else if (d > du) {
+						_d.setValue(v, du);
+						_p.setValue(v, e);
+					}
+				}, _links);
+			}
+			
+			data.nodes.visit(function(n:NodeSprite):void {
+				var e:EdgeSprite = _p.getValue(n);
+				if (e) _e.setValue(e, true);
+			});
+		}
+		
+	} // end of class LinkDistance
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/ShortestPaths.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/ShortestPaths.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/ShortestPaths.as	(revision 15)
@@ -0,0 +1,156 @@
+package gssim.gssimstudio.editor.flare.analytics.graph
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.heap.FibonacciHeap;
+	import gssim.gssimstudio.editor.flare.util.heap.HeapNode;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+	
+	/**
+	 * Calculates the shortest paths to a source node using Dijkstra's algorithm.
+	 * Nodes are annotated with both the total distance and their incoming edge
+	 * along the shortest path.
+	 */
+	public class ShortestPaths extends Operator
+	{
+		private var _d:Property = Property.$("props.distance");
+		private var _p:Property = Property.$("props.predecessor");
+		private var _e:Property = Property.$("props.onpath");
+		private var _w:Function = null;
+		
+		/** The source node from which to compute the shortest paths. */
+		public var source:NodeSprite;
+		
+		/** A function determining edge weights used in the shortest path
+		 *  calculation. When setting this value, one can pass in either a
+		 *  Function, which should take an EdgeSprite as input and return a
+		 *  Number as output, or a String, in which case the string will be
+		 *  used as a property name from which to retrieve the edge weight
+		 *  value from an EdgeSprite instance. If the value is null (the
+		 *  default) all edges will be assumed to have weight 1.
+		 *  
+		 *  <p><b>NOTE:</b> Edge weights must be greater than or equal to zero!
+		 *  </p> */
+		public function get edgeWeight():Function { return _w; }
+		public function set edgeWeight(w:*):void {
+			if (w==null) {
+				_w = null;
+			} else if (w is String) {
+				_w = Property.$(String(w)).getValue;
+			} else if (w is Function) {
+				_w = w;
+			} else {
+				throw new Error("Unrecognized edgeWeight value. " +
+					"The value should be a Function or String.");
+			}
+		}
+		
+		/** The property in which to store the link distance. This property
+		 *  is used to annotate nodes with the minimum link distance to one of
+		 *  the source nodes. The default value is "props.distance". */
+		public function get distanceField():String { return _d.name; }
+		public function set distanceField(f:String):void { _d = Property.$(f); }
+		
+		/** The property in which to store incoming edges along a shortest
+		 *  path. This property is used to annotate nodes with the incoming
+		 *  along a shortest path from one of the source nodes. By following
+		 *  sequential incoming edges, one can recreate the shortest path from
+		 *  the nearest source node. The default value is "props.incoming". */
+		public function get incomingField():String { return _p.name; }
+		public function set incomingField(f:String):void { _p = Property.$(f); }
+		
+		/** The property in which to store a path inclusion flag for edges.
+		 *  This property is used to mark edges as belonging to one of the
+		 *  computed shortest paths: <code>true</code> indicates that the edge
+		 *  participates in a shortest path, <code>false</code> indicates that
+		 *  the edge does not lie along a shortest path. The default value is
+		 *  "props.onpath". */
+		public function get onpathField():String { return _p.name; }
+		public function set onpathField(f:String):void { _p = Property.$(f); }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new ShortestPaths operator.
+		 * @param source the source node from which to measure shortest paths
+		 * @param edgeWeight the edge weight values. This can either be a
+		 *  <code>Function</code> that returns weight values or a
+		 *  <code>String</code> providing the name of a property to look up on
+		 *  <code>EdgeSprite</code> instances.
+		 */
+		public function ShortestPaths(source:NodeSprite=null,
+			edgeWeight:*=null)
+		{
+			this.source = source;
+			this.edgeWeight = edgeWeight;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			calculate(visualization.data, source, _w);
+		}
+		
+		/**
+		 * Calculates the shortest paths from a source node.
+		 * @param data the data set containing a graph
+		 * @param n the source node from which to measure path lengths
+		 * @param w a function returning weight values for edges. If null,
+		 *  all edges will be assumed to have equal weight.
+		 */
+		public function calculate(data:Data, s:NodeSprite, w:Function=null):void
+		{
+			var u:NodeSprite, ud:HeapNode, dg:int;
+			var dir:Boolean = data.directedEdges;
+			
+			// initialize heap and node distances
+			var heap:FibonacciHeap = new FibonacciHeap();
+			data.edges.setProperty(_e.name, false);
+			data.nodes.visit(function(n:NodeSprite):void {
+				_p.setValue(n, null);
+				n.props.heapNode = heap.insert(n);
+			});
+			heap.decreaseKey(HeapNode(s.props.heapNode), 0);
+			
+			while (!heap.empty) {
+				ud = heap.removeMin();
+				u  = NodeSprite(ud.data);
+				u.visitEdges(function(e:EdgeSprite):void {
+					var v :NodeSprite = e.other(u);
+					var vd:HeapNode   = v.props.heapNode;
+					var ew:Number     = (w==null ? 1 : w(e));
+					// ensure edge weight is non-negative
+					if (ew < 0)
+						throw new Error("Edge weights must be non-negative!");
+						
+					// perform the relaxation
+					if (vd.key > ud.key + ew) {
+						heap.decreaseKey(vd, ud.key + ew);
+						_p.setValue(v, e);
+					}
+				}, dir ? NodeSprite.OUT_LINKS : NodeSprite.GRAPH_LINKS);
+			}
+			
+			data.nodes.visit(function(n:NodeSprite):void {
+				var hn:HeapNode = n.props.heapNode;
+				delete n.props.heapNode;
+				_d.setValue(n, hn.key);
+				var e:EdgeSprite = _p.getValue(n);
+				if (e) _e.setValue(e, true);
+			});
+		}
+		
+		public function getShortestPathTo(v:NodeSprite):Array
+		{
+			var path:Array = [v], e:EdgeSprite;
+			while ((e = _p.getValue(v)) != null) {
+				path.unshift(v = e.other(v));
+			}
+			return path;
+		}
+		
+	} // end of class ShortestPaths
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/MaxFlowMinCut.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/MaxFlowMinCut.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/MaxFlowMinCut.as	(revision 15)
@@ -0,0 +1,205 @@
+package gssim.gssimstudio.editor.flare.analytics.graph
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+	
+	import flash.utils.Dictionary;
+	
+	/**
+	 * Calculates the maximum flow along edges of a graph using the
+	 * Edmonds-Karp method. Each edge in the graph will be annotated with its
+	 * final flow value, as well as a boolean value indicating if the edge
+	 * is part of the minimum cut of the flow graph. Nodes are annotated with
+	 * their partition according to the minimum cut: a partition value of 0
+	 * indicates the source-side of the cut, a value of 1 indicates the
+	 * sink-side of the cut.
+	 */
+	public class MaxFlowMinCut extends Operator
+	{
+		private var _c:Property = Property.$("props.capacity");
+		private var _f:Property = Property.$("props.flow");
+		private var _p:Property = Property.$("props.predecessor");
+		private var _k:Property = Property.$("props.mincut");
+		private var _cap:Function = null;
+		
+		/** The property in which to store computed flow values. This property
+		 *  is used to annotate edges with the computed flow. The default
+		 *  value is "props.flow". */
+		public function get flowField():String { return _f.name; }
+		public function set flowField(f:String):void { _f = Property.$(f); }
+		
+		/** The property in which to store minimum-cut data. The default value
+		 *  is "props.mincut". This property is used to annotate nodes with
+		 *  their partition (0 for source-side, 1 for sink-side) and to
+		 *  annotate edges with min-cut membership (true if part of the
+		 *  minimum cut, false otherwise). */
+		public function get mincutField():String { return _k.name; }
+		public function set mincutField(f:String):void { _k = Property.$(f); }
+		
+		/** The source node for which to compute the max flow. */
+		public var source:NodeSprite;
+		/** The sink node for which to compute the max flow. */
+		public var sink:NodeSprite;
+		/** A function defining the edge capacities for flow. When setting
+		 *  this value, one can pass in either a Function, which should take an
+		 *  EdgeSprite as input and return a Number as output, or a String, in
+		 *  which case the string will be used as a property name from which to
+		 *  retrieve the edge capacity value from an EdgeSprite instance.
+		 *  If the value is null (the default) all edges will be assumed to have
+		 *  capacity 1.
+		 *  
+		 *  <p><b>NOTE:</b> Capacities must be greater than or equal to zero!
+		 *  </p> */
+		public function get edgeCapacity():Function { return _cap; }
+		public function set edgeCapacity(c:*):void {
+			if (c==null) {
+				_cap = null;
+			} else if (c is String) {
+				_cap = Property.$(String(c)).getValue;
+			} else if (c is Function) {
+				_cap = c;
+			} else {
+				throw new Error("Unrecognized edgeCapacity value. " +
+					"The value should be a Function or String.");
+			}
+		}
+		
+		/** The computed maximum flow value. This value is zero by default
+		 *  and is populated once the max flow calculation is run. */
+		public function get maxFlow():Number { return _maxFlow; }
+		
+		private var _data:Data, _s:NodeSprite, _t:NodeSprite;
+		private var _maxFlow:Number = 0;
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new MaxFlowMinCut operator.
+		 * @param source the source node in the flow graph
+		 * @param sink the sink node in the flow graph
+		 * @param edgeCapacity the edge capacity values. This can either be a
+		 *  <code>Function</code> that returns capacity values or a
+		 *  <code>String</code> providing the name of a property to look up on
+		 *  <code>EdgeSprite</code> instances.
+		 */
+		public function MaxFlowMinCut(source:NodeSprite=null,
+			sink:NodeSprite=null, edgeCapacity:*=null)
+		{
+			this.source = source;
+			this.sink = sink;
+			this.edgeCapacity = edgeCapacity;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			calculate(visualization.data, source, sink, _cap);
+		}
+		
+		/**
+		 * Calculates the maximum flow and minimum cut for the given data 
+		 * @param data the data set containing the flow graph
+		 * @param s the source node in the flow graph
+		 * @param t the target or "sink" node in the flow graph
+		 * @param c a function returning capacity values for edges
+		 */
+		public function calculate(data:Data, s:NodeSprite, t:NodeSprite,
+			c:Function=null):void
+        {
+        	_data = data; _s = s; _t = t;
+        	_data.nodes.visit(function(n:NodeSprite):void {
+        		_c.setValue(n, 0);
+        		_f.setValue(n, 0);
+        		_p.setValue(n, null);
+        	});
+        	_data.edges.visit(function(e:EdgeSprite):void {
+        		var cap:Number = (c==null ? 1 : c(e));
+				if (cap < 0) throw new Error("Edge capacity must be > 0!");
+        		_c.setValue(e, cap);
+        	});
+            
+            // update flows until no more augmenting path
+            while (augmentingPath()) {
+            	var cap:Number = _c.getValue(_t);
+            	_maxFlow += cap;
+            	var v:NodeSprite = _t, u:NodeSprite, e:EdgeSprite;
+            	while (v != _s) {
+            		e = _p.getValue(v);
+            		u = e.source;
+            		
+            		_f.setValue(e, _f.getValue(e) + cap);
+            		_c.setValue(e, _c.getValue(e) - cap);
+            		v = u;
+            	}
+            }
+            minCut();
+            
+            _data.visit(_c.deleteValue);
+            _data.nodes.visit(_p.deleteValue);
+        }
+ 
+ 		/**
+ 		 * Uses a breadth-first-search to find an augmenting path that
+ 		 * increases the net flow through the graph.
+ 		 */
+        private function augmentingPath():Boolean
+        {
+        	_data.nodes.setProperty(_c.name, Number.MAX_VALUE);
+        	var visited:Dictionary = new Dictionary();
+        	var queue:Array = [_s], u:NodeSprite, b:Boolean;
+        	
+        	while (queue.length > 0) {
+        		visited[u = queue.shift()] = true;
+        		b = u.visitEdges(function(e:EdgeSprite):Boolean {
+        			// get residual capacity on edge
+        			var cap:Number = _c.getValue(e);
+        			var v:NodeSprite = e.other(u);
+        			if (visited[v] || cap <= 0) return false;
+        			
+        			_c.setValue(v, Math.min(_c.getValue(u), cap));
+        			_p.setValue(v, e);
+        			if (v == _t) return true;
+        			queue.push(v);
+        			return false;
+        		}, NodeSprite.OUT_LINKS);
+        		if (b) return true;
+        	}
+            return false;
+        }
+        
+        /**
+         * Given that the max flow has been computed, finds the minimum-cut
+         * of the flow graph, annotating nodes according to their partition
+         * (source-side or sink-side) and annotating the edges that constitute
+         * the minimum cut.
+         */
+        private function minCut():void
+        {
+        	_data.nodes.setProperty(_k.name, 1);
+        	var visited:Dictionary = new Dictionary();
+        	var queue:Array = [_s], u:NodeSprite, b:Boolean;
+        	
+        	while (queue.length > 0) {
+        		visited[u = queue.shift()] = true;
+        		_k.setValue(u, 0);
+        		
+        		u.visitEdges(function(e:EdgeSprite):void {
+        			var v:NodeSprite = e.other(u);
+        			if (!(visited[v] || _c.getValue(e) <= 0))
+        				queue.push(v);
+        		}, NodeSprite.OUT_LINKS);
+        	}
+            
+            _data.edges.visit(function(e:EdgeSprite):void {
+            	var up:int = _k.getValue(e.source);
+            	var vp:int = _k.getValue(e.target);
+            	_k.setValue(e, (up==0 && vp==1));
+            });
+        }
+
+	} // end of class MaxFlowMinCut
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/SpanningTree.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/SpanningTree.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/SpanningTree.as	(revision 15)
@@ -0,0 +1,94 @@
+package gssim.gssimstudio.editor.flare.analytics.graph
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.TreeBuilder;
+	import gssim.gssimstudio.editor.flare.vis.operator.IOperator;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+
+	/**
+	 * Calculates a spanning tree for a graph structure. This operator can
+	 * create spanning trees by breadth-first search, depth-first search, or by
+	 * computing a minimum spanning tree. The default is to find a minimum
+	 * spanning tree, which in turn defaults to breadth-first search if no edge
+	 * weight function is provided.
+	 * 
+	 * <p>This class can annotate graph edges as belonging to the spanning tree
+	 * (done if the <code>annotateEdges</code> property is true), and can
+	 * construct a <code>Tree</code> instance (done if the
+	 * <code>buildTree<code> property is true). Generated <code>Tree<code>
+	 * instances are stored in the <code>tree</code> property. Generated trees
+	 * contain the original nodes and edges in the input graph, and any
+	 * previous parent or child links for input nodes will be cleared and
+	 * overwritten.</p>
+	 * 
+	 * <p>This class extends the TreeBuilder class to also function as an
+	 * operator that can be added to a visualization's operator list.</p>
+	 */
+	public class SpanningTree extends TreeBuilder implements IOperator
+	{
+		private var _vis:Visualization;
+		private var _enabled:Boolean;
+		
+		/** @inheritDoc */
+		public function get visualization():Visualization { return _vis; }
+		public function set visualization(v:Visualization):void {
+			_vis = v; setup();
+		}
+		
+		/** @inheritDoc */
+		public function get enabled():Boolean { return _enabled; }
+		public function set enabled(b:Boolean):void { _enabled = b; }
+		
+		/** @inheritDoc */
+		public function set parameters(params:Object):void
+		{
+			Operator.applyParameters(this, params);
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new SpanningTree operator
+		 * @param policy the spanning tree creation policy. The default is
+		 *  <code>SpanningTree.MINIMUM_SPAN</code>
+		 * @param buildTree if true, this operator will build a new
+		 *  <code>Tree</code> instance containing the spanning tree
+		 * @param annotateEdges if true, this operator will annotate the
+		 *  edges of the original graph as belonging to the spanning tree
+		 * @param root the root node from which to compute the spanning tree
+		 * @param edgeWeight the edge weight values. This can either be a
+		 *  <code>Function</code> that returns weight values or a
+		 *  <code>String</code> providing the name of a property to look up on
+		 *  <code>EdgeSprite</code> instances.
+		 */
+		public function SpanningTree(policy:String=null,
+			buildTree:Boolean=false, annotateEdges:Boolean=true,
+			root:NodeSprite=null, edgeWeight:*=null)
+		{
+			super(policy, buildTree, annotateEdges, root, edgeWeight);
+		}
+		
+		/** @inheritDoc */
+		public function operate(t:Transitioner=null):void
+		{
+			super.calculate(visualization.data, root);
+		}
+		
+		/** @inheritDoc */
+		public function setup():void
+		{
+			// for subclasses
+		}
+		
+		// -- MXML ------------------------------------------------------------
+		
+		/** @private */
+		public function initialized(document:Object, id:String):void
+		{
+			// do nothing
+		}
+		
+	} // end of class SpanningTree
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/BetweennessCentrality.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/BetweennessCentrality.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/graph/BetweennessCentrality.as	(revision 15)
@@ -0,0 +1,120 @@
+package gssim.gssimstudio.editor.flare.analytics.graph
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+	
+	/**
+	 * Calculates betweenness centrality measures for nodes in a graph.
+	 * The algorithm used is due to Ulrik Brandes, as published in the
+	 * <a href="http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf">
+	 * Journal of Mathematical Sociology, 25(2):163-177, 2001</a>.
+	 */
+	public class BetweennessCentrality extends Operator
+	{
+		private var _bc:Property = Property.$("props.centrality");
+		
+		/** The property in which to store the centrality score. This property
+		 *  is used to annotate nodes with their betweenness centrality score.
+		 *  The default value is "props.centrality". */
+		public function get centralityField():String { return _bc.name; }
+		public function set centralityField(f:String):void { _bc = Property.$(f); }
+		
+		/** Flag indicating the type of links to follow in the graph. The
+		 *  default is <code>NodeSprite.GRAPH_LINKS</code>. */
+		public var links:int = NodeSprite.GRAPH_LINKS;
+
+		/**
+		 * Creates a new BetweennessCentrality operator.
+		 */
+		public function BetweennessCentrality()
+		{
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			calculate(visualization.data);
+		}
+		
+		/**
+		 * Calculates the betweenness centrality values for the given data set. 
+		 * @param data the data set for which to compute centrality measures
+		 */
+		public function calculate(data:Data):void
+		{
+			var nodes:DataList = data.nodes; var N:int = nodes.length, i:int;
+			var n:NodeSprite, v:NodeSprite, w:NodeSprite;
+			var si:Score, sv:Score, sw:Score;
+			
+			nodes.visit(function(n:NodeSprite):void {
+				_bc.setValue(n, 0);
+				n.props._score = new Score();
+			});
+			
+			for (i=0; i<N; ++i) {
+				nodes.visit(function(n:NodeSprite):void {
+					n.props._score.reset();
+				});
+				n  = nodes[i];
+				si = n.props._score;
+				si.paths = 1;
+				si.distance = 0;
+				
+				var stack:Array = [];
+				var queue:Array = [n];
+				
+				while (queue.length > 0) {
+					stack.push(v = queue.shift()); si = v.props._score;
+					
+					v.visitNodes(function(w:NodeSprite):void {
+						var sv:Score = si, sw:Score = w.props._score;
+						if (sw.distance < 0) {
+							queue.push(w);
+							sw.distance = sv.distance + 1;
+						}
+						if (sw.distance == sv.distance + 1) {
+							sw.paths += sv.paths;
+							sw.predecessors.push(v);
+						}
+					}, links);
+				}
+				while (stack.length > 0) {
+					w = stack.pop(); sw = w.props._score;
+					for each (v in sw.predecessors) {
+						sv = v.props._score;
+						sv.dependency += (sv.paths/sw.paths) * (1+sw.dependency);
+					}
+					if (w !== n) sw.centrality += sw.dependency;
+				}
+			}
+			
+			nodes.visit(function(n:NodeSprite):void {
+				_bc.setValue(n, n.props._score.centrality);
+				delete n.props._score;
+			});
+		}
+		
+	} // end of class BetweennessCentrality
+}
+
+import gssim.gssimstudio.editor.flare.util.Arrays;
+
+/** Helper class for storing intermediate centrality computations */
+class Score {
+	public var dependency:Number = 0;
+	public var distance:Number = -1;
+	public var paths:Number = 0;
+	public var predecessors:Array = [];
+	public var centrality:Number = 0;
+	
+	public function reset():void {
+		Arrays.clear(predecessors);
+		dependency = 0;
+		distance = -1;
+		paths = 0;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/optimization/AspectRatioBanker.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/optimization/AspectRatioBanker.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/analytics/optimization/AspectRatioBanker.as	(revision 15)
@@ -0,0 +1,188 @@
+package gssim.gssimstudio.editor.flare.analytics.optimization
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.scale.Scale;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.axis.CartesianAxes;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+	
+	/**
+	 * Computes an optimized aspect ratio for drawing a line chart.
+	 * This operator will update the visualization's bounds to reflect the
+	 * optimized aspect ratio. Place this operator in an
+	 * <code>OperatorList</code> <b>before</b> the <code>AxisLayout</code>
+	 * operator, and set the <code>dataField</code> property to be the
+	 * same as the axis data field that should be banked. For example, in
+	 * a time series chart with time on the x-axis, the data field for this
+	 * operator should be the same as the data field used for the y-axis.
+	 * By default this class assumes that the data field is being laid out
+	 * on the y-axis. If this is not the case (e.g., you have a vertically
+	 * oriented line chart), be sure to set the <code>bankYAxis</code>
+	 * property to <code>false</code>.
+	 */
+	public class AspectRatioBanker extends Operator
+	{
+		private var _z:Property = null;
+		
+		/** The maximum width for the visualization bounds. */
+		public var maxWidth:Number = 500;
+		/** The maximum height for the visualization bounds. */
+		public var maxHeight:Number = 500;
+		/** Indicates if the data field is on the y-axis (default true). */
+		public var bankYAxis:Boolean = true;
+		/** The banking function to use. This is a function that takes an
+		 *  array of Numbers as input and returns an aspect ratio. It is
+		 *  expected that this function will be one of the static functions of
+		 *  this class. The default is <code>averageAbsoluteAngle</code>. */
+		public var banker:Function = averageAbsoluteAngle;
+		
+		/** The data field of the values to bank. */
+		public function get dataField():String { return _z.name; }
+		public function set dataField(f:String):void {
+			_z = Property.$(f); setup();
+		}
+		
+		/**
+		 * Creates a new AspectRatioBanker. 
+		 * @param dataField the data field from which pull numeric values from
+		 *  NodeSprites. These values are then used to determine the optimal
+		 *  aspect ratio.
+		 */
+		public function AspectRatioBanker(dataField:String=null,
+			bankYAxis:Boolean=true, maxWidth:Number=500, maxHeight:Number=500)
+		{
+			if (dataField) _z = Property.$(dataField);
+			this.bankYAxis = bankYAxis;
+			this.maxWidth  = maxWidth;
+			this.maxHeight = maxHeight;
+		}
+
+		// --------------------------------------------------------------------
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			if (_z == null) return; // nothing to do
+			
+			// extract data
+			var v:Array = [];
+			visualization.data.nodes.visit(function(d:DataSprite):void {
+				v.push(_z.getValue(d));
+			});
+			
+			// compute the aspect ratio (= width/height)
+			var ar:Number = banker(v);
+			if (!bankYAxis) ar = 1/ar;
+			ar = adjustToAxes(visualization, ar);
+			
+			// set visualization bounds and update axes
+			visualization.setAspectRatio(ar, maxWidth, maxHeight);
+			visualization.axes.update(t);
+		}
+		
+		/**
+		 * Adjusts an aspect ratio for the "data rectangle" bounding the data
+		 * points to an new ratio that factors in the axis scale settings.
+		 * @param ar the desired aspect ratio of the data rectangle
+		 * @return the adjusted aspect ratio
+		 */
+		private static function adjustToAxes(vis:Visualization, ar:Number):Number
+		{
+			// get axis scales for each data field
+			var axes:CartesianAxes = vis.xyAxes;
+			var xsc:Scale = axes.xAxis.axisScale;
+			var ysc:Scale = axes.yAxis.axisScale;
+			
+			// compute adjusted aspect ratio: this is the inverse aspect ratio
+			// of the interpolated data rectangle in data space multipled by
+			// the desired aspect ratio for the data rectangle in screen space
+			var dy:Number, dx:Number;			
+			dy = ysc.interpolate(ysc.max) - ysc.interpolate(ysc.min);
+			dx = xsc.interpolate(xsc.max) - xsc.interpolate(xsc.min);
+			return ar * dy / dx;
+		}
+
+		// --------------------------------------------------------------------
+		
+		/**
+	     * Bank the average absolute orientation to 45 degrees.
+	     * "Slopeless" lines are culled before the banking is computed.
+	     * Solved using Newton-Raphson iteration.
+	     * <pre>
+	     * a     = aspect ratio (as height / width)
+	     * ci    = normalized slope = N * abs(y_i+1 - y_i) / range(y)
+	     * x     = a * ci
+	     * f(a)  = sum(atan(x)) / N - pi/4
+	     * f'(a) = sum(ci/(1 + x^2)) / N
+	     * </pre>
+	     * @param a an array of data values to be banked. It is assumed that
+	     *  values on the opposite axis are evenly spaced.
+	     * @return the optimized aspect ratio
+	     */
+	    public static function averageAbsoluteAngle(a:Array):Number
+	    {
+	    	var alpha:Number=0, alpha_p:Number, f:Number, fprime:Number;
+	    	var x:Number, Ry:Number = Arrays.max(a) - Arrays.min(a);
+	    	var N:int = a.length-1, iter:int = 0, i:int, j:int;
+	
+	        // compute constants, perform culling
+	        var c:Array = [];
+	        for (i=0, j=0; i<N; ++i) {
+	        	var slope:Number = Math.abs(a[i+1] - a[i]) / Ry;
+	        	if (slope > 1e-5) c.push(N * slope);
+	        }
+	        N = c.length;
+	        
+	        // Newton-Raphson iteration
+	        do {
+	            iter++;
+	            alpha_p = alpha;
+	            
+	            // compute function and function derivative
+	            f = fprime = 0;
+	            for (i=0; i<N; ++i) {
+	                x = c[i] * alpha;
+	                f += Math.atan(x);
+	                fprime += c[i] / (1 + x*x);
+	            }
+	            f /= N;
+	            fprime /= N;
+	            f -= Math.PI/4;
+	            
+	            // apply the Newton-Raphson increment
+	            alpha = alpha_p - f/fprime;
+	            
+	         // finish iteration when update difference drops beneath tolerance
+	         } while (Math.abs(alpha - alpha_p) > 1e-5);
+	         
+	         return 1/alpha;
+	    }
+	    
+	    /**
+	     * Bank the median absolute slope to 45 degrees.
+	     * "Slopeless" lines are culled before the banking is computed.
+	     * @param a an array of data values to be banked. It is assumed that
+	     *  values on the opposite axis are evenly spaced.
+	     * @return the optimized aspect ratio
+	     */
+	    public static function medianAbsoluteSlope(a:Array):Number
+	    {
+	    	var slopes:Array = [], i:int;
+	    	var yRange:Number = Arrays.max(a) - Arrays.min(a);
+	        
+	        for (i=1; i<a.length; ++i) {
+	            var slope:Number = Math.abs(a[i] - a[i-1]);
+	            if (slope/yRange > 1e-5) {
+	                slopes.push(slope);
+	            }
+	        }
+	        slopes.sort(Array.NUMERIC);
+	        var median:Number = slopes[slopes.length>>1];
+	        return (median*(a.length-1)) / yRange;
+	    }
+
+	} // end of class AspectRatioBanker
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/IScaleMap.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/IScaleMap.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/IScaleMap.as	(revision 15)
@@ -0,0 +1,61 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	/**
+	 * Interface used by classes which support mapping between
+	 * spatial (x,y) coordinates and values in a data scale. For example,
+	 * both an axis or legend range should provide this functionality.
+	 */
+	public interface IScaleMap
+	{
+		/**
+		 * Returns the x-coordinate corresponding to the lower end of the scale.
+		 * @return the x-coordinate for the minimum value
+		 */
+		function get x1():Number;
+		
+		/**
+		 * Returns the y-coordinate corresponding to the lower end of the scale.
+		 * @return the y-coordinate for the minimum value
+		 */
+		function get y1():Number;
+		
+		/**
+		 * Returns the x-coordinate corresponding to the upper end of the scale.
+		 * @return the x-coordinate for the maximum value
+		 */
+		function get x2():Number;
+		
+		/**
+		 * Returns the y-coordinate corresponding to the upper end of the scale.
+		 * @return the y-coordinate for the maximum value
+		 */
+		function get y2():Number;
+		
+		/**
+		 * Returns the scale value corresponding to a given coordinate.
+		 * @param x the x-coordinate
+		 * @param y the y-coordinate
+		 * @param stayInBounds if true, x,y values outside the current layout
+		 * bounds will be snapped to the bounds. If false, the value lookup
+		 * will attempt to extrapolate beyond the scale bounds. This value
+		 * is true be default.
+		 * @return the scale value corresponding to the given coordinate.
+		 */		
+		function value(x:Number, y:Number, stayInBounds:Boolean=true):Object;
+        
+        /**
+         * Returns the x-coordinate corresponding to the given scale value
+         * @param val the scale value to lookup
+         * @return the x-coordinate at which that scale value is placed
+         */        
+        function X(val:Object):Number;
+        
+        /**
+         * Returns the y-coordinate corresponding to the given scale value
+         * @param val the scale value to lookup
+         * @return the y-coordinate at which that scale value is placed
+         */
+        function Y(val:Object):Number;
+        
+	} // end of interface IScaleMap
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/OrdinalScale.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/OrdinalScale.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/OrdinalScale.as	(revision 15)
@@ -0,0 +1,130 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	import flash.utils.Dictionary;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	
+	/**
+	 * Scale for ordered sequential data. This supports both numeric and
+	 * non-numeric data, and simply places each element in sequence using
+	 * the ordering found in the input data array.
+	 */
+	public class OrdinalScale extends Scale
+	{
+		private var _ordinals:Array;
+		private var _lookup:Dictionary;
+
+		/**
+		 * Creates a new OrdinalScale.
+		 * @param ordinals an ordered array of data values to include in the
+		 *  scale
+		 * @param flush the flush flag for scale padding
+		 * @param copy flag indicating if a copy of the input data array should
+		 *  be made. True by default.
+		 * @param labelFormat the formatting pattern for value labels
+		 */
+		public function OrdinalScale(ordinals:Array=null, flush:Boolean=false,
+			copy:Boolean=true, labelFormat:String=null)
+        {
+        	_ordinals = (ordinals==null ? new Array() :
+        				 copy ? Arrays.copy(ordinals) : ordinals);
+            buildLookup();
+            _flush = flush;
+            _format = labelFormat;
+        }
+        
+        /** @inheritDoc */
+		public override function get scaleType():String {
+			return ScaleType.ORDINAL;
+		}
+        
+        /** @inheritDoc */
+        public override function clone() : Scale
+        {
+        	return new OrdinalScale(_ordinals, _flush, true, _format);
+        }
+        
+		// -- Properties ------------------------------------------------------
+
+		/** The number of distinct values in this scale. */
+		public function get length():int
+		{
+			return _ordinals.length;
+		}
+
+		/** The ordered data array defining this scale. */
+		public function get ordinals():Array
+		{
+			return _ordinals;
+		}
+		public function set ordinals(val:Array):void
+		{
+			_ordinals = val; buildLookup();
+		}
+
+		/**
+		 * Builds a lookup table for mapping values to their indices.
+		 */
+		protected function buildLookup():void
+        {
+        	_lookup = new Dictionary();
+            for (var i:uint = 0; i < _ordinals.length; ++i)
+                _lookup[ordinals[i]] = i;
+        }
+		
+		/** @inheritDoc */
+		public override function get min():Object { return _ordinals[0]; }
+		
+		/** @inheritDoc */
+		public override function get max():Object { return _ordinals[_ordinals.length-1]; }
+		
+		// -- Scale Methods ---------------------------------------------------
+		
+		/**
+		 * Returns the index of the input value in the ordinal array
+		 * @param value the value to lookup
+		 * @return the index of the input value. If the value is not contained
+		 *  in the ordinal array, this method returns -1.
+		 */
+		public function index(value:Object):int
+		{
+			var idx:* = _lookup[value];
+			return (idx==undefined ? -1 : int(idx));
+		}
+		
+		/** @inheritDoc */
+		public override function interpolate(value:Object):Number
+		{
+			if (_ordinals==null || _ordinals.length==0) return 0.5;
+			
+			if (_flush) {
+				return Number(_lookup[value]) / (_ordinals.length-1);
+			} else {
+				return (0.5 + _lookup[value]) / _ordinals.length;
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function lookup(f:Number):Object
+		{
+			if (_flush) {
+				return _ordinals[int(Math.round(f*(_ordinals.length-1)))];
+			} else {
+				f = Math.max(0, Math.min(1, f*_ordinals.length - 0.5));
+				return _ordinals[int(Math.round(f))];
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function values(num:int=-1):Array
+		{
+			var a:Array = new Array();
+			var stride:Number = num<0 ? 1 
+				: Math.max(1, Math.floor(_ordinals.length / num));
+			for (var i:uint = 0; i < _ordinals.length; i += stride) {
+				a.push(_ordinals[i]);
+			}
+			return a;
+		}
+
+	} // end of class OrdinalScale
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/LinearScale.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/LinearScale.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/LinearScale.as	(revision 15)
@@ -0,0 +1,47 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	import gssim.gssimstudio.editor.flare.util.Strings;
+	
+	/**
+	 * Scale that spaces values linearly along the scale range. This is the
+	 * default scale for numeric types.
+	 */
+	public class LinearScale extends QuantitativeScale
+	{
+		/**
+		 * Creates a new LinearScale.
+		 * @param min the minimum data value
+		 * @param max the maximum data value
+		 * @param base the number base to use
+		 * @param flush the flush flag for scale padding
+		 * @param labelFormat the formatting pattern for value labels
+		 */
+		public function LinearScale(min:Number=0, max:Number=0, base:Number=10,
+			flush:Boolean=false, labelFormat:String=Strings.DEFAULT_NUMBER)
+		{
+			super(min, max, base, flush, labelFormat);
+		}
+		
+		/** @inheritDoc */
+		public override function get scaleType():String {
+			return ScaleType.LINEAR;
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Scale {
+			return new LinearScale(_dmin, _dmax, _base, _flush, _format);
+		}
+		
+		/** @inheritDoc */
+		protected override function interp(val:Number):Number {
+			return Maths.invLinearInterp(val, _smin, _smax);
+		}
+		
+		/** @inheritDoc */
+		public override function lookup(f:Number):Object {
+			return Maths.linearInterp(f, _smin, _smax);
+		}
+		
+	} // end of class LinearScale
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/QuantitativeScale.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/QuantitativeScale.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/QuantitativeScale.as	(revision 15)
@@ -0,0 +1,179 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	import gssim.gssimstudio.editor.flare.util.Strings;
+	
+	/**
+	 * Base class for representing quantitative numerical data scales.
+	 */
+	public class QuantitativeScale extends Scale
+	{
+		/** The minimum data value. */
+		protected var _dmin:Number;
+		/** The maximum data value. */
+		protected var _dmax:Number;
+		/** The minimum value of the scale range. */
+		protected var _smin:Number;
+		/** The maximum value of the scale range. */
+		protected var _smax:Number;
+		/** The number base of the scale. */
+		protected var _base:Number;
+
+		/**
+		 * Creates a new QuantitativeScale.
+		 * @param min the minimum data value
+		 * @param max the maximum data value
+		 * @param base the number base to use
+		 * @param flush the flush flag for scale padding
+		 * @param labelFormat the formatting pattern for value labels
+		 */
+		public function QuantitativeScale(min:Number=0, max:Number=0, base:Number=10,
+			flush:Boolean=false, labelFormat:String=Strings.DEFAULT_NUMBER)
+		{
+			this.base = base;
+			this.dataMin = min;
+			this.dataMax = max;
+			this.flush = flush;
+			this.labelFormat = labelFormat;
+		}
+
+		/** @inheritDoc */
+		public override function clone() : Scale
+		{
+			throw new Error("This is an abstract class");
+		}
+
+		// -- Properties ------------------------------------------------------
+		
+		/** @inheritDoc */
+		public override function set flush(val:Boolean):void
+		{
+			_flush = val; updateScale();
+		}
+		
+		/** @inheritDoc */
+		public override function get min():Object { return dataMin; }
+		public override function set min(o:Object):void { dataMin = Number(o); }
+		
+		/** @inheritDoc */
+		public override function get max():Object { return dataMax; }
+		public override function set max(o:Object):void { dataMax = Number(o); }
+		
+		/** The minimum data value. This property is the same as the
+		 *  <code>minimum</code> property, but properly typed. */
+		public function get dataMin():Number
+		{
+			return _dmin;
+		}
+		public function set dataMin(val:Number):void
+		{
+			_dmin = val; updateScale();
+		}
+
+		/** The maximum data value. This property is the same as the
+		 *  <code>maximum</code> property, but properly typed. */
+		public function get dataMax():Number
+		{
+			return _dmax;
+		}
+		public function set dataMax(val:Number):void
+		{
+			_dmax = val; updateScale();
+		}
+		
+		/** The minimum value of the scale range. */
+		public function get scaleMin():Number
+		{
+			return _smin;
+		}
+		
+		/** The maximum value of the scale range. */
+		public function get scaleMax():Number
+		{
+			return _smax;
+		}
+		
+		/** The number base used by the scale.
+		 *  By default, base 10 numbers are assumed. */
+		public function get base():Number
+		{
+			return _base;
+		}
+		public function set base(val:Number):void
+		{
+			_base = val;
+		}
+		
+		// -- Scale Methods ---------------------------------------------------
+
+		/**
+		 * Updates the scale range after a change to the data range.
+		 */
+		protected function updateScale():void
+		{
+			if (!_flush) {
+                var step:Number = getStep(_dmin, _dmax);
+                _smin = Math.floor(_dmin / step) * step;
+                _smax = Math.ceil(_dmax / step) * step;
+            } else {
+                _smin = _dmin;
+                _smax = _dmax;
+            }
+		}
+
+		/**
+		 * Returns the default step value between label values. The step is
+		 * computed according to the current number base.
+		 * @param min the minimum scale value
+		 * @param max the maximum scale value
+		 * @return the default step value between label values
+		 */
+		protected function getStep(min:Number, max:Number):Number
+		{
+			var range:Number = max - min;
+			var exp:Number = Math.round(Maths.log(range, _base)) - 1;
+			return Math.pow(base, exp);
+		}
+		
+		/** @inheritDoc */
+		public override function lookup(f:Number):Object
+		{
+			return null;
+		}
+		
+		/** @inheritDoc */
+		public override function interpolate(value:Object):Number
+		{
+			return interp(Number(value));
+		}
+
+		/**
+		 * Returns the interpolation fraction for the given input number.
+		 * @param val the input number
+		 * @return the interpolation fraction for the input value
+		 */
+		protected function interp(val:Number):Number
+		{
+			return -1;
+		}
+		
+		/** @inheritDoc */
+		public override function values(num:int=-1):/*Number*/Array
+		{
+			var a:Array = new Array();
+			var range:Number = _smax - _smin;
+
+			if (range == 0) {
+				a.push(_smin);
+			} else {
+				var step:Number = getStep(_smin, _smax);
+				var stride:Number = num<0 ? 1 : Math.max(1, Math.floor(range/(step*num)));
+				for (var x:Number = _smin; x <= _smax; x += stride*step) {
+					a.push(x);
+				}
+			}
+			return a;
+		}
+
+	} // end of class QuantitativeScale
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/TimeScale.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/TimeScale.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/TimeScale.as	(revision 15)
@@ -0,0 +1,204 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	import gssim.gssimstudio.editor.flare.util.Dates;
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	
+	/**
+	 * Scale for timelines represented using <code>Date</code> values. This
+	 * scale represents a linear, quantitative time line. The class attempts
+	 * to automatically configure date value labels based on the time span
+	 * between the earliest and latest date in the scale. The label formatting
+	 * pattern can also be manually set using the <code>labelFormat</code>
+	 * property.
+	 */
+	public class TimeScale extends Scale
+	{
+		private var _dmin:Date = new Date(0);
+		private var _dmax:Date = new Date(0);
+		private var _smin:Date;
+		private var _smax:Date;
+		private var _autofmt:Boolean = true;
+		
+		/**
+		 * Creates a new TimeScale.
+		 * @param min the minimum (earliest) date value
+		 * @param max the maximum (latest) date value
+		 * @param flush the flush flag for scale padding
+		 * @param labelFormat the formatting pattern for value labels
+		 */
+		public function TimeScale(min:Date=null, max:Date=null,
+			flush:Boolean=false, labelFormat:String=null)
+		{
+			if (min) this.dataMin = min;
+			if (max) this.dataMax = max;
+			this.flush = flush;
+			this.labelFormat = labelFormat;
+		}
+		
+		/** @inheritDoc */
+		public override function get scaleType():String {
+			return ScaleType.TIME;
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Scale {
+			return new TimeScale(_dmin, _dmax, _flush, _format);
+		}
+		
+		// -- Properties ------------------------------------------------------
+		
+		/** @inheritDoc */
+		public override function set flush(val:Boolean):void
+		{
+			_flush = val; updateScale();
+		}
+		
+		/** @inheritDoc */
+		public override function get labelFormat():String
+		{
+			return (_autofmt ? null : super.labelFormat);
+		}
+		
+		public override function set labelFormat(fmt:String):void
+		{
+			if (fmt != null) {
+				super.labelFormat = fmt;
+				_autofmt = false;
+			} else {
+				_autofmt = true;
+				updateScale();
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function get min():Object { return dataMin; }
+		public override function set min(o:Object):void { dataMin = o as Date; }
+		
+		/** @inheritDoc */
+		public override function get max():Object { return dataMax; }
+		public override function set max(o:Object):void { dataMax = o as Date; }
+		
+		/** The minimum (earliest) Date value in the underlying data.
+		 *  This property is the same as the <code>minimum</code>
+		 *  property, but properly typed. */
+		public function get dataMin():Date
+		{
+			return _dmin;
+		}
+		public function set dataMin(val:Date):void
+		{
+			_dmin = val; updateScale();
+		}
+
+		/** The maximum (latest) Date value in the underlying data.
+		 *  This property is the same as the <code>maximum</code>
+		 *  property, but properly typed. */
+		public function get dataMax():Date
+		{
+			return _dmax;
+		}
+		public function set dataMax(val:Date):void
+		{
+			_dmax = val; updateScale();
+		}
+		
+		/** The minimum (earliest) Date value in the scale. */
+		public function get scaleMin():Date
+		{
+			return _smin;
+		}
+		
+		/** The maximum (latest) Date value in the underlying data. */
+		public function get scaleMax():Date
+		{
+			return _smax;
+		}
+		
+		// -- Scale Methods ---------------------------------------------------
+		
+		/** @inheritDoc */
+		public override function interpolate(value:Object):Number
+		{
+			var t:Number = value is Date ? (value as Date).time : Number(value);
+			return Maths.invLinearInterp(t, _smin.time, _smax.time);
+		}
+		
+		/** @inheritDoc */
+		public override function lookup(f:Number):Object
+		{
+			var t:Number = Math.round(Maths.linearInterp(f, _smin.time, _smax.time));
+			return new Date(t);
+		}
+		
+		/**
+		 * Updates the scale range when the data range is changed.
+		 */
+		protected function updateScale():void
+		{
+			var span:int = Dates.timeSpan(_dmin, _dmax);
+			if (_flush) {
+				_smin = _dmin;
+				_smax = _dmax;
+			} else {
+				_smin = Dates.roundTime(_dmin, span, false);
+				_smax = Dates.roundTime(_dmax, span, true);
+			}
+			if (_autofmt) {
+				super.labelFormat = formatString(span);
+			}
+		}
+		
+		/**
+		 * Determines the format string to be used based on a measure of
+		 * the time span covered by this scale.
+		 * @param span the time span covered by this scale. Should use the
+		 *  format of the <code>flare.util.Dates</code> class.
+		 * @return the label formatting pattern
+		 */
+		protected function formatString(span:int):String
+		{
+			if (span >= Dates.YEARS) {
+				return "yyyy";
+			} else if (span == Dates.MONTHS) {
+				return "MMM";
+			} else if (span == Dates.DAYS) {
+				return "d";
+			} else if (span == Dates.HOURS) {
+				return "h:mmt";
+			} else if (span == Dates.MINUTES) {
+				return "h:mmt";
+			} else if (span == Dates.SECONDS) {
+				return "h:mm:ss";
+			} else {
+				return "s.fff";
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function values(num:int=-1):Array
+		{   
+            var a:Array = new Array();
+            var span:int = Dates.timeSpan(_dmin, _dmax);
+            var step:Number = Dates.timeStep(span);
+			var max:Number = _smax.time;
+            var d:Date = _flush ? Dates.roundTime(scaleMin, span, true) : scaleMin;
+
+            if (span < Dates.MONTHS) {
+            	for (var x:Number = _smin.time; x <= max; x += step) {
+            		a.push(new Date(x));
+            	}
+            } else if (span == Dates.MONTHS) {
+            	for (; d.time <= max; d = Dates.addMonths(d,1)) {
+            		a.push(d);
+            	}
+            } else {
+            	var y:int = int(step);
+            	for (; d.time <= max; d = Dates.addYears(d,y)) {
+            		a.push(d);
+            	}
+            }
+			return a;
+		}
+		
+	} // end of class TimeScale
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/Scale.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/Scale.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/Scale.as	(revision 15)
@@ -0,0 +1,141 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	import gssim.gssimstudio.editor.flare.util.Strings;
+	
+	import mx.core.IMXMLObject;
+	
+	/**
+	 * Base class for all data scale types.
+	 */
+	public class Scale implements IMXMLObject
+	{
+		/** Flag indicating if the scale bounds should be flush with the data.
+		 *  False by default, thereby allowing some padding space on the end
+		 *  of the scale. */
+		protected var _flush:Boolean = false;
+		/** Formatting pattern for formatting labels for scale values.
+		 *  @see flare.util.Strings#format */
+		protected var _format:String = null;
+
+		/**
+		 * Flag indicating if the scale bounds should be flush with the data.
+		 * If true, the scale should be flush with the data range, such that
+		 * the min and max values should sit directly on the extremes of the
+		 * scale. If false, the scale should be padded as needed to make the
+		 * scale more readable and human-friendly.
+		 */
+		public function get flush() : Boolean { return _flush; }
+		public function set flush(val:Boolean) : void { _flush = val; }
+
+		/**
+		 * Formatting pattern for formatting labels for scale values.
+		 * For details about the various formatting patterns, see the
+		 * documentation for the <code>Strings.format</code> method.
+		 * @see flare.util.String#format
+		 */
+		public function get labelFormat() : String
+		{
+			return _format==null ? null : _format.substring(3,_format.length-1);
+		}
+		public function set labelFormat(fmt:String) : void
+		{
+			_format = (fmt==null ? fmt : "{0:"+fmt+"}");
+		}
+		
+		/** A string indicating the type of scale this is. */
+		public function get scaleType():String
+		{
+			return ScaleType.UNKNOWN;
+		}
+		
+		/** The minimum data value backing this scale. Note that the actual
+		 *  minimum scale value may be lower if the scale is not flush. */
+		public function get min():Object
+		{
+			throw new Error("Unsupported property");
+		}
+		public function set min(o:Object):void
+		{
+			throw new Error("Unsupported property");
+		}
+		
+		/** The maximum data value backing this scale. Note that the actual
+		 *  maximum scale value may be higher if the scale is not flush. */
+		public function get max():Object
+		{
+			throw new Error("Unsupported property");
+		}
+		public function set max(o:Object):void
+		{
+			throw new Error("Unsupported property");
+		}
+		
+		/**
+		 * Returns a cloned copy of the scale.
+		 * @return a cloned scale.
+		 */
+		public function clone() : Scale
+		{
+			return null;
+		}
+		
+		/**
+		 * Returns an interpolation fraction indicating the position of the input
+		 * value within the scale range.
+		 * @param value a data value for which to return an interpolation
+		 *  fraction along the data scale
+		 * @return the interpolation fraction of the value in the data scale
+		 */
+		public function interpolate(value:Object) : Number
+		{
+			return 0;
+		}
+
+		/**
+		 * Returns a string label representing a value in this scale.
+		 * The labelFormat property determines how the value will be formatted.
+		 * @param value the data value to get the string label for
+		 * @return a string label for the value
+		 */
+		public function label(value:Object) : String
+		{
+			if (_format == null) {
+				return value==null ? "" : value.toString();
+			} else {
+				return Strings.format(_format, value);
+			}
+		}
+
+		/**
+		 * Performs a reverse lookup, returning an object value corresponding
+		 * to a interpolation fraction along the scale range.
+		 * @param f the interpolation fraction
+		 * @return the scale value at the interpolation fraction. May return
+		 *  null if no value corresponds to the input fraction.
+		 */
+		public function lookup(f:Number) : Object
+		{
+			return null;
+		}
+
+		/**
+		 * Returns a set of label values for this scale.
+		 * @param num a desired target number of labels. This parameter is
+		 *  handled idiosyncratically by different scale sub-classes.
+		 * @return an array of label values for the scale
+		 */ 
+		public function values(num:int=-1) : Array
+		{
+			return null;
+		}
+		
+		// -- MXML ------------------------------------------------------------
+		
+		/** @private */
+		public function initialized(document:Object, id:String):void
+		{
+			// do nothing
+		}
+		
+	} // end of class Scale
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/LogScale.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/LogScale.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/LogScale.as	(revision 15)
@@ -0,0 +1,113 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	import gssim.gssimstudio.editor.flare.util.Strings;
+	
+	/**
+	 * Scale that performs a log transformation of the data. The base of the
+	 * logarithm is determined by the <code>base</code> property.
+	 */
+	public class LogScale extends QuantitativeScale
+	{
+		private var _zero:Boolean = false;
+		
+		/**
+		 * Creates a new LogScale.
+		 * @param min the minimum data value
+		 * @param max the maximum data value
+		 * @param base the number base to use
+		 * @param flush the flush flag for scale padding
+		 * @param labelFormat the formatting pattern for value labels
+		 */
+		public function LogScale(min:Number=0, max:Number=0, base:Number=10,
+			flush:Boolean=false, labelFormat:String=Strings.DEFAULT_NUMBER)
+		{
+			super(min, max, base, flush, labelFormat);
+		}
+		
+		/** @inheritDoc */
+		public override function get scaleType():String {
+			return ScaleType.LOG;
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Scale {
+			return new LogScale(_dmin, _dmax, _base, _flush, _format);
+		}
+		
+		/** @inheritDoc */
+		protected override function interp(val:Number):Number {
+			if (_zero) {
+				return Maths.invAdjLogInterp(val, _smin, _smax, _base);
+			} else {
+				return Maths.invLogInterp(val, _smin, _smax, _base);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function lookup(f:Number):Object
+		{
+			if (_zero) {
+				return Maths.adjLogInterp(f, _smin, _smax, _base);
+			} else {
+				return Maths.logInterp(f, _smin, _smax, _base);
+			}
+		}
+		
+		/** @inheritDoc */
+		protected override function updateScale():void
+		{
+			_zero = (_dmin < 0 && _dmax > 0);
+			if (!_flush) {
+				_smin = Maths.logFloor(_dmin, _base);
+				_smax = Maths.logCeil(_dmax, _base);
+				
+				if (_zero) {
+					if (Math.abs(_dmin) < _base) _smin = Math.floor(_dmin);
+					if (Math.abs(_dmax) < _base) _smax = Math.ceil(_dmax);	
+				}
+			} else {
+				_smin = _dmin;
+				_smax = _dmax;
+			}	
+		}
+		
+		private function log(x:Number):Number {
+			if (_zero) {
+				// distorts the scale to accomodate zero
+				return Maths.adjLog(x, _base);
+			} else {
+				// uses a zero-symmetric logarithmic scale
+				return Maths.symLog(x, _base);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function values(num:int=-1):Array
+		{
+			var vals:Array = new Array();
+			
+			var beg:int = int(Math.round(log(_smin)));
+			var end:int = int(Math.round(log(_smax)));
+			
+			if (beg == end && beg > 0 && Math.pow(10, beg) > _smin) {
+            	--beg; // decrement to generate more values
+   			}
+   			
+            var i:int, j:int, b:Number, v:Number = _zero?-1:1;
+            for (i = beg; i <= end; ++i)
+            {
+	           	if (i==0 && v<=0) { vals.push(v); vals.push(0); }
+	           	v = _zero && i<0 ? -Math.pow(_base,-i) : Math.pow(_base,i);
+	           	b = _zero && i<0 ? Math.pow(_base,-i-1) : v;
+	            	
+	           	for (j = 1; j < _base; ++j, v += b) {
+	           		if (v > _smax) return vals;
+	           		vals.push(v);
+	           	}
+            }
+            return vals;
+        }
+		
+	} // end of class LogScale
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/ScaleType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/ScaleType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/ScaleType.as	(revision 15)
@@ -0,0 +1,55 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	/**
+	 * Constants defining known scale types, such as linear, log, and
+	 * date/time scales.
+	 */
+	public class ScaleType
+	{
+		/** Constant indicating an unknown scale. */
+		public static const UNKNOWN:String = "unknown";
+		/** Constant indicating a categorical scale. */
+		public static const CATEGORIES:String = "categories";
+		/** Constant indicating an ordinal scale. */
+		public static const ORDINAL:String = "ordinal";
+		/** Constant indicating a linear numeric scale. */
+		public static const LINEAR:String = "linear";
+		/** Constant indicating a root-transformed numeric scale. */
+		public static const ROOT:String = "root";
+		/** Constant indicating a log-transformed numeric scale. */
+		public static const LOG:String = "log";
+		/** Constant indicating a quantile scale. */
+		public static const QUANTILE:String = "quantile";
+		/** Constant indicating a date/time scale. */
+		public static const TIME:String = "time";
+		
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function ScaleType() {
+			throw new Error("This is an abstract class.");
+		}
+		
+		/**
+		 * Tests if a given scale type indicates an ordinal scale 
+		 * @param type the scale type
+		 * @return true if the type indicates an ordinal scale, false otherwise
+		 */
+		public static function isOrdinal(type:String):Boolean
+		{
+			return type==ORDINAL || type==CATEGORIES;
+		}
+		
+		/**
+		 * Tests if a given scale type indicates a quantitative scale 
+		 * @param type the scale type
+		 * @return true if the type indicates a quantitative scale,
+		 *  false otherwise
+		 */
+		public static function isQuantitative(type:String):Boolean
+		{
+			return type==LINEAR || type==ROOT || type==LOG;
+		}
+		
+	} // end of class ScaleType
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/QuantileScale.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/QuantileScale.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/QuantileScale.as	(revision 15)
@@ -0,0 +1,81 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	import gssim.gssimstudio.editor.flare.util.Strings;
+	
+	/**
+	 * Scale that organizes data into discrete bins by quantiles.
+	 * For example, the quantile scale can be used to create a discrete size
+	 * encoding by statistically dividing the data into bins. Quantiles are
+	 * computed using the <code>flare.util.Maths.quantile</code> method.
+	 * 
+	 * @see flare.util.Maths#quantile
+	 */
+	public class QuantileScale extends Scale
+	{
+		private var _quantiles:Array;
+		
+		/** @inheritDoc */
+		public override function get flush():Boolean { return true; }
+		public override function set flush(val:Boolean):void { /* nothing */ }
+		
+		/** @inheritDoc */
+		public override function get min():Object { return _quantiles[0]; }
+		
+		/** @inheritDoc */
+		public override function get max():Object { return _quantiles[_quantiles.length-1]; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new QuantileScale.
+		 * @param n the number of quantiles desired
+		 * @param values the data values to organized into quantiles
+		 * @param sorted flag indicating if the input values array is
+		 *  already pre-sorted
+		 * @param labelFormat the formatting pattern for value labels
+		 */
+		public function QuantileScale(n:int, values:Array,
+			sorted:Boolean=false, labelFormat:String=Strings.DEFAULT_NUMBER)
+		{
+			_quantiles = (n<0 ? values : Maths.quantile(n, values, !sorted));
+			this.labelFormat = labelFormat;
+		}
+		
+		/** @inheritDoc */
+		public override function get scaleType():String {
+			return ScaleType.QUANTILE;
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Scale
+		{
+			return new QuantileScale(-1, _quantiles, false, _format);
+		}
+		
+		/** @inheritDoc */
+		public override function interpolate(value:Object):Number
+		{
+			return Maths.invQuantileInterp(Number(value), _quantiles);
+		}
+		
+		/** @inheritDoc */
+		public override function lookup(f:Number):Object
+		{
+			return Maths.quantileInterp(f, _quantiles);
+		}
+		
+		/** @inheritDoc */
+		public override function values(num:int=-1):/*Number*/Array
+		{
+			var a:Array = new Array();
+			var stride:int = num<0 ? 1 : 
+				int(Math.max(1, Math.floor(_quantiles.length/num)));
+			for (var i:uint=0; i<_quantiles.length; i += stride) {
+				a.push(_quantiles[i]);
+			}
+			return a;
+		}
+		
+	} // end of class QuantileScale
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/RootScale.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/RootScale.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/scale/RootScale.as	(revision 15)
@@ -0,0 +1,58 @@
+package gssim.gssimstudio.editor.flare.scale
+{
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	import gssim.gssimstudio.editor.flare.util.Strings;
+	
+	/**
+	 * Scale that performs a root transformation of the data. This could be a
+	 * square root or any arbitrary power.
+	 */
+	public class RootScale extends QuantitativeScale
+	{
+		private var _pow:Number = 2;
+		
+		/** The power of the root transform. A value of 2 indicates a square
+		 *  root, 3 a cubic root, etc. */
+		public function get power():Number { return _pow; }
+		public function set power(p:Number):void { _pow = p; }
+		
+		/**
+		 * Creates a new RootScale.
+		 * @param min the minimum data value
+		 * @param max the maximum data value
+		 * @param base the number base to use
+		 * @param flush the flush flag for scale padding
+		 * @param labelFormat the formatting pattern for value labels
+		 */
+		public function RootScale(min:Number=0, max:Number=0, base:Number=10,
+								  flush:Boolean=false, pow:Number=2,
+								  labelFormat:String=Strings.DEFAULT_NUMBER)
+		{
+			super(min, max, base, flush, labelFormat);
+			_pow = pow;
+		}
+		
+		/** @inheritDoc */
+		public override function get scaleType():String {
+			return ScaleType.ROOT;
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Scale {
+			return new RootScale(_dmin, _dmax, _base, _flush, _pow, _format);
+		}
+		
+		/** @inheritDoc */
+		protected override function interp(val:Number):Number {
+			if (_pow==2) return Maths.invSqrtInterp(val, _smin, _smax);
+			return Maths.invRootInterp(val, _smin, _smax, _pow);
+		}
+		
+		/** @inheritDoc */
+		public override function lookup(f:Number):Object {
+			if (_pow==2) return Maths.sqrtInterp(f, _smin, _smax);
+			return Maths.rootInterp(f, _smin, _smax, _pow);
+		}
+		
+	} // end of class RootScale
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSet.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSet.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSet.as	(revision 15)
@@ -0,0 +1,25 @@
+package gssim.gssimstudio.editor.flare.data
+{	
+	/**
+	 * A data set is a collection of data tables.
+	 */
+	public class DataSet
+	{
+		/**
+		 * Creates a new DataSet.
+		 * @param nodes a data table of node data
+		 * @param edges a data table of edge data (optional, for graphs only)
+		 */
+		public function DataSet(nodes:DataTable, edges:DataTable=null) {
+			this.nodes = nodes;
+			this.edges = edges;
+		}
+
+		/** A DataTable of nodes (or table rows). */
+		public var nodes:DataTable = null;
+		
+		/** A DataTable of edges. */
+		public var edges:DataTable = null;
+
+	} // end of class DataSet
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataUtil.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataUtil.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataUtil.as	(revision 15)
@@ -0,0 +1,112 @@
+package gssim.gssimstudio.editor.flare.data
+{	
+	/**
+	 * Utility class for parsing and representing data field values.
+	 */
+	public class DataUtil
+	{
+		/** Constant indicating a numeric data type. */
+		public static const NUMBER:int  = 0;
+		/** Constant indicating an integer data type. */
+		public static const INT:int     = 1;
+		/** Constant indicating a Date data type. */
+		public static const DATE:int    = 2;
+		/** Constant indicating a String data type. */
+		public static const STRING:int  = 3;
+		/** Constant indicating an arbitrary Object data type. */
+		public static const OBJECT:int  = 4;
+		/** Constant indicating a boolean data type. */
+		public static const BOOLEAN:int = 5;
+		
+		/**
+		 * Parse an input value given its data type.
+		 * @param val the value to parse
+		 * @param type the data type to parse as
+		 * @return the parsed data value
+		 */
+		public static function parseValue(val:Object, type:int):Object
+		{
+			switch (type) {
+				case NUMBER:
+					return Number(val);
+				case INT:	
+					return int(val);
+				case BOOLEAN:
+					return Boolean(val);
+				case DATE:
+					var t:Number = val is Number ? Number(val) 
+												 : Date.parse(String(val));
+					return isNaN(t) ? null : new Date(t);
+				case STRING:
+					return String(val);
+				default:		return val;
+			}
+		}
+		
+		/**
+		 * Returns the data type for the input string value. This method
+		 * attempts to parse the value as a number of different data types.
+		 * If successful, the matching data type is returned. If no parse
+		 * succeeds, this method returns the <code>STRING</code> constant.
+		 * @param s the string to parse
+		 * @return the inferred data type of the string contents
+		 */
+		public static function type(s:String):int
+		{
+			if (!isNaN(Number(s))) return NUMBER;
+			if (!isNaN(Date.parse(s))) return DATE;
+			return STRING;
+		}
+		
+		/**
+		 * Infers the data schema by checking values of the input data.
+		 * @param tuples an array of data tuples
+		 * @return the inferred schema
+		 */
+		public static function inferSchema(tuples:Array):DataSchema
+		{
+			if (tuples==null || tuples.length==0) return null;
+			
+			var header:Array = [];
+			for (var name:String in tuples[0]) {
+				header.push(name);
+			}
+			var types:Array = new Array(header.length);
+			
+			// initialize data types
+			for (var col:int=0; col<header.length; ++col) {
+				types[col] = DataUtil.type(tuples[0][header[col]]);
+			}
+			
+			// now process data to infer types
+			for (var i:int = 2; i<tuples.length; ++i) {
+				var tuple:Object = tuples[i];
+				for (col=0; col<header.length; ++col) {
+					name = header[col];
+					var value:Object = tuple[name];
+					if (types[col] == -1 || value==null) continue;
+					
+					var type:int = 
+						value is Boolean ? BOOLEAN :
+						value is Date ? DATE :
+						value is int ? INT :
+						value is Number ? NUMBER :
+						value is String ? STRING : OBJECT;
+
+					if (types[col] != type) {
+						types[col] = -1;
+					}
+				}
+			}
+			
+			// finally, we create the schema
+			var schema:DataSchema = new DataSchema();
+			for (col=0; col<header.length; ++col) {
+				schema.addField(new DataField(header[col],
+					types[col]==-1 ? DataUtil.STRING : types[col]));
+			}
+			return schema;
+		}
+		
+	} // end of class DataUtil
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/JSONConverter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/JSONConverter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/JSONConverter.as	(revision 15)
@@ -0,0 +1,76 @@
+package gssim.gssimstudio.editor.flare.data.converters
+{
+	import com.adobe.serialization.json.JSON;
+	
+	import gssim.gssimstudio.editor.flare.data.DataField;
+	import gssim.gssimstudio.editor.flare.data.DataSchema;
+	import gssim.gssimstudio.editor.flare.data.DataSet;
+	import gssim.gssimstudio.editor.flare.data.DataTable;
+	import gssim.gssimstudio.editor.flare.data.DataUtil;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	
+	import flash.utils.ByteArray;
+	import flash.utils.IDataInput;
+	import flash.utils.IDataOutput;
+
+	/**
+	 * Converts data between JSON (JavaScript Object Notation) strings and
+	 * flare DataSet instances.
+	 */
+	public class JSONConverter implements IDataConverter
+	{
+		/**
+		 * @inheritDoc
+		 */
+		public function read(input:IDataInput, schema:DataSchema=null):DataSet
+		{
+			var data:Array;
+			return new DataSet(new DataTable(
+				data = parse(input.readUTFBytes(input.bytesAvailable), schema),
+				schema ? schema : DataUtil.inferSchema(data)
+			));
+		}
+		
+		/**
+		 * Converts data from a JSON string into ActionScript objects.
+		 * @param input the loaded input data
+		 * @param schema a data schema describing the structure of the data.
+		 *  Schemas are optional in many but not all cases.
+		 * @param data an array in which to write the converted data objects.
+		 *  If this value is null, a new array will be created.
+		 * @return an array of converted data objects. If the <code>data</code>
+		 *  argument is non-null, it is returned.
+		 */
+		public function parse(text:String, schema:DataSchema):Array
+		{
+			var json:Object = JSON.decode(text) as Object;
+			var list:Array = json as Array;
+			
+			if (schema != null) {
+				if (schema.dataRoot) {
+					// if nested, extract data array
+					list = Property.$(schema.dataRoot).getValue(json);
+				}
+				// convert value types according to schema
+				for each (var t:Object in list) {
+					for each (var f:DataField in schema.fields) {
+						t[f.name] = DataUtil.parseValue(t[f.name], f.type);
+					}
+				}
+			}
+			return list;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public function write(data:DataSet, output:IDataOutput=null):IDataOutput
+		{
+			var tuples:Array = data.nodes.data;
+			if (output==null) output = new ByteArray();
+			output.writeUTFBytes(JSON.encode(tuples));
+			return output;
+		}
+		
+	} // end of class JSONConverter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/GraphMLConverter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/GraphMLConverter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/GraphMLConverter.as	(revision 15)
@@ -0,0 +1,298 @@
+package gssim.gssimstudio.editor.flare.data.converters
+{
+	import gssim.gssimstudio.editor.flare.data.DataField;
+	import gssim.gssimstudio.editor.flare.data.DataSchema;
+	import gssim.gssimstudio.editor.flare.data.DataSet;
+	import gssim.gssimstudio.editor.flare.data.DataTable;
+	import gssim.gssimstudio.editor.flare.data.DataUtil;
+	
+	import flash.utils.ByteArray;
+	import flash.utils.IDataInput;
+	import flash.utils.IDataOutput;
+
+	/**
+	 * Converts data between GraphML markup and flare DataSet instances.
+	 * <a href="http://graphml.graphdrawing.org/">GraphML</a> is a
+	 * standardized XML format supporting graph structure and typed data
+	 * schemas for both nodes and edges.
+	 */
+	public class GraphMLConverter implements IDataConverter
+	{    
+		// -- reader ----------------------------------------------------------
+		
+		/** @inheritDoc */
+		public function read(input:IDataInput, schema:DataSchema=null):DataSet
+		{
+			var str:String = input.readUTFBytes(input.bytesAvailable);
+			var idx:int = str.indexOf(GRAPHML);
+			if (idx > 0) {
+				str = str.substr(0, idx+GRAPHML.length) + 
+					str.substring(str.indexOf(">", idx));
+			}
+			return parse(XML(str), schema);
+		}
+		
+		/**
+		 * Parses a GraphML XML object into a DataSet instance.
+		 * @param graphml the XML object containing GraphML markup
+		 * @param schema a DataSchema (typically null, as GraphML contains
+		 *  schema information)
+		 * @return the parsed DataSet instance
+		 */
+		public function parse(graphml:XML, schema:DataSchema=null):DataSet
+		{
+			var lookup:Object = {};
+			var nodes:Array = [], n:Object;
+			var edges:Array = [], e:Object;
+			var id:String, sid:String, tid:String;
+			var def:Object, type:int;
+			var group:String, attrName:String, attrType:String;
+			
+			var nodeSchema:DataSchema = new DataSchema();
+			var edgeSchema:DataSchema = new DataSchema();
+			var schema:DataSchema;
+			
+			// set schema defaults
+			nodeSchema.addField(new DataField(ID, DataUtil.STRING));
+			edgeSchema.addField(new DataField(ID, DataUtil.STRING));
+			edgeSchema.addField(new DataField(SOURCE, DataUtil.STRING));
+			edgeSchema.addField(new DataField(TARGET, DataUtil.STRING));
+			edgeSchema.addField(new DataField(DIRECTED, DataUtil.BOOLEAN,
+									DIRECTED == graphml.graph.@edgedefault));
+			
+			// parse data schema
+			for each (var key:XML in graphml..key) {
+				id       = key.@[ID].toString();
+				group    = key.@[FOR].toString();
+				attrName = key.@[ATTRNAME].toString();
+				type     = toType(key.@[ATTRTYPE].toString());
+				def = key[DEFAULT].toString();
+				def = def != null && def.length > 0
+					? DataUtil.parseValue(def, type) : null;
+				
+				schema = (group==EDGE ? edgeSchema : nodeSchema);
+				schema.addField(new DataField(attrName, type, def, id));
+			}
+			
+			// parse nodes
+			for each (var node:XML in graphml..node) {
+				id = node.@[ID].toString();
+				lookup[id] = (n = parseData(node, nodeSchema));
+				nodes.push(n);
+			}
+			
+			// parse edges
+			for each (var edge:XML in graphml..edge) {
+				id  = edge.@[ID].toString();
+				sid = edge.@[SOURCE].toString();
+				tid = edge.@[TARGET].toString();
+				
+				// error checking
+				if (!lookup.hasOwnProperty(sid))
+					error("Edge "+id+" references unknown node: "+sid);
+				if (!lookup.hasOwnProperty(tid))
+					error("Edge "+id+" references unknown node: "+tid);
+								
+				edges.push(e = parseData(edge, edgeSchema));
+			}
+			
+			return new DataSet(
+				new DataTable(nodes, nodeSchema),
+				new DataTable(edges, edgeSchema)
+			);
+		}
+		
+		private function parseData(node:XML, schema:DataSchema):Object {
+			var n:Object = {};
+			var name:String, field:DataField, value:Object;
+			
+			// set default values
+			for (var i:int=0; i<schema.numFields; ++i) {
+				field = schema.getFieldAt(i);
+				n[field.name] = field.defaultValue;
+			}
+			
+			// get attribute values
+			for each (var attr:XML in node.@*) {
+				name = attr.name().toString();
+				field = schema.getFieldByName(name);
+				n[name] = DataUtil.parseValue(attr[0].toString(), field.type);
+			}
+			
+			// get data values in XML
+			for each (var data:XML in node.data) {
+				field = schema.getFieldById(data.@[KEY].toString());
+				name = field.name;
+				n[name] = DataUtil.parseValue(data[0].toString(), field.type);
+			}
+			
+			return n;
+		}
+
+		// -- writer ----------------------------------------------------------
+		
+		/** @inheritDoc */
+		public function write(data:DataSet, output:IDataOutput=null):IDataOutput
+		{			
+			// init GraphML
+			var graphml:XML = new XML(GRAPHML_HEADER);
+			
+			// add schema
+			graphml = addSchema(graphml, data.nodes.schema, NODE, NODE_ATTR);
+			graphml = addSchema(graphml, data.edges.schema, EDGE, EDGE_ATTR);
+			
+			// add graph data
+			var graph:XML = new XML(<graph/>);
+			var ed:Object = data.edges.schema.getFieldByName(DIRECTED).defaultValue;
+			graph.@[EDGEDEF] = ed==DIRECTED ? DIRECTED : UNDIRECTED;
+			addData(graph, data.nodes.data, data.nodes.schema, NODE, NODE_ATTR);
+			addData(graph, data.edges.data, data.edges.schema, EDGE, EDGE_ATTR);
+			graphml = graphml.appendChild(graph);
+			
+			if (output == null) output = new ByteArray();
+			output.writeUTFBytes(graphml.toXMLString());
+			return output;
+		}
+		
+		private static function addSchema(xml:XML, schema:DataSchema,
+			group:String, attrs:Object):XML
+		{
+			var field:DataField;
+			
+			for (var i:int=0; i<schema.numFields; ++i) {
+				field = schema.getFieldAt(i);
+				if (attrs.hasOwnProperty(field.name)) continue;
+				
+				var key:XML = new XML(<key/>);
+				key.@[ID] = field.id;
+				key.@[FOR] = group;
+				key.@[ATTRNAME] = field.name;
+				key.@[ATTRTYPE] = fromType(field.type);
+			
+				if (field.defaultValue != null) {
+					var def:XML = new XML(<default/>);
+					def.appendChild(toString(field.defaultValue, field.type));
+					key.appendChild(def);
+				}
+				
+				xml = xml.appendChild(key);
+			}
+			return xml;
+		}
+		
+		private static function addData(xml:XML, tuples:Array,
+			schema:DataSchema, tag:String, attrs:Object):void
+		{
+			for each (var tuple:Object in tuples) {
+				var x:XML = new XML("<"+tag+"/>");
+				
+				for (var name:String in tuple) {
+					var field:DataField = schema.getFieldByName(name);
+					if (tuple[name] == field.defaultValue) continue;
+					if (attrs.hasOwnProperty(name)) {
+						// add as attribute
+						x.@[name] = toString(tuple[name], field.type);
+					} else {
+						// add as data child tag
+						var data:XML = new XML(<data/>);
+						data.@[KEY] = field.id;
+						data.appendChild(toString(tuple[name], field.type));
+						x.appendChild(data);
+					}
+				}
+				
+				xml.appendChild(x);
+			}
+		}	
+		
+		// -- static helpers --------------------------------------------------
+		
+		private static function toString(o:Object, type:int):String
+		{
+			return o.toString(); // TODO: formatting control?
+		}
+		
+		private static function toType(type:String):int {
+			switch (type) {
+				case INT:
+				case INTEGER:
+					return DataUtil.INT;
+				case LONG:
+				case FLOAT:
+				case DOUBLE:
+				case REAL:
+					return DataUtil.NUMBER;
+				case BOOLEAN:
+					return DataUtil.BOOLEAN;
+				case DATE:
+					return DataUtil.DATE;
+				case STRING:
+				default:
+					return DataUtil.STRING;
+			}
+		}
+		
+		private static function fromType(type:int):String {
+			switch (type) {
+				case DataUtil.INT: 		return INT;
+				case DataUtil.BOOLEAN: 	return BOOLEAN;
+				case DataUtil.NUMBER:	return DOUBLE;
+				case DataUtil.DATE:		return DATE;
+				case DataUtil.STRING:
+				default:				return STRING;
+			}
+		}
+		
+		private static function error(msg:String):void {
+			throw new Error(msg);
+		}
+		
+		// -- constants -------------------------------------------------------
+		
+		private static const NODE_ATTR:Object = {
+			"id":1
+		}
+		private static const EDGE_ATTR:Object = {
+			"id":1, "directed":1, "source":1, "target":1
+		};
+		
+		private static const GRAPHML_HEADER:String = "<graphml/>";
+		//	"<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"" 
+        //    +" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+        //    +" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns"
+        //    +" http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">"
+        //    +"</graphml>";
+        
+        private static const GRAPHML:String    = "graphml";
+		private static const ID:String         = "id";
+	    private static const GRAPH:String      = "graph";
+	    private static const EDGEDEF:String    = "edgedefault";
+	    private static const DIRECTED:String   = "directed";
+	    private static const UNDIRECTED:String = "undirected";
+	    
+	    private static const KEY:String        = "key";
+	    private static const FOR:String        = "for";
+	    private static const ALL:String        = "all";
+	    private static const ATTRNAME:String   = "attr.name";
+	    private static const ATTRTYPE:String   = "attr.type";
+	    private static const DEFAULT:String    = "default";
+	    
+	    private static const NODE:String   = "node";
+	    private static const EDGE:String   = "edge";
+	    private static const SOURCE:String = "source";
+	    private static const TARGET:String = "target";
+	    private static const DATA:String   = "data";
+	    private static const TYPE:String   = "type";
+	    
+	    private static const INT:String = "int";
+	    private static const INTEGER:String = "integer";
+	    private static const LONG:String = "long";
+	    private static const FLOAT:String = "float";
+	    private static const DOUBLE:String = "double";
+	    private static const REAL:String = "real";
+	    private static const BOOLEAN:String = "boolean";
+	    private static const STRING:String = "string";
+	    private static const DATE:String = "date";
+		
+	} // end of class GraphMLConverter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/Converters.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/Converters.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/Converters.as	(revision 15)
@@ -0,0 +1,27 @@
+package gssim.gssimstudio.editor.flare.data.converters
+{	
+	/**
+	 * Factory class for looking up the appropriate IDataConverter for a
+	 * given data format.
+	 */
+	public class Converters
+	{
+		private static var _lookup:Object = {
+			"json":new JSONConverter(),
+			"tab":new DelimitedTextConverter("\t"),
+			"graphml":new GraphMLConverter()
+		};
+		
+		/**
+		 * Returns a data converter for the input format type.
+		 * @param type a format string (e.g., "tab" or "json").
+		 * @return a data converter for the provided format, or null if no
+		 *  matching converter was found.
+		 */
+		public static function lookup(type:String):IDataConverter
+		{
+			return _lookup[type.toLowerCase()];
+		}
+		
+	} // end of class Converters
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/IDataConverter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/IDataConverter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/IDataConverter.as	(revision 15)
@@ -0,0 +1,36 @@
+package gssim.gssimstudio.editor.flare.data.converters
+{
+	import gssim.gssimstudio.editor.flare.data.DataSchema;
+	import gssim.gssimstudio.editor.flare.data.DataSet;
+	
+	import flash.utils.IDataInput;
+	import flash.utils.IDataOutput;
+	
+	/**
+	 * Interface for data converters that map between an external data file
+	 * format and ActionScript objects (e.g., Arrays and Objects).
+	 */
+	public interface IDataConverter
+	{
+		/**
+		 * Converts data from an external format into ActionScript objects.
+		 * @param input the loaded input data
+		 * @param schema a data schema describing the structure of the data.
+		 *  Schemas are optional in many but not all cases.
+		 * @return a DataSet instance containing converted data objects.
+		 */
+		function read(input:IDataInput, schema:DataSchema=null):DataSet;
+		
+		/**
+		 * Converts data from ActionScript objects into an external format.
+		 * @param data the data set to write.
+		 * @param output an object to which to write the output. If this value
+		 *  is null, a new <code>ByteArray</code> will be created.
+		 * @return the converted data. If the <code>output</code> parameter is
+		 *  non-null, it is returned. Otherwise the return value will be a
+		 *  newly created <code>ByteArray</code>
+		 */
+		function write(data:DataSet, output:IDataOutput=null):IDataOutput;
+		
+	} // end of interface IDataConverter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/DelimitedTextConverter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/DelimitedTextConverter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/converters/DelimitedTextConverter.as	(revision 15)
@@ -0,0 +1,143 @@
+package gssim.gssimstudio.editor.flare.data.converters
+{
+	import gssim.gssimstudio.editor.flare.data.DataField;
+	import gssim.gssimstudio.editor.flare.data.DataSchema;
+	import gssim.gssimstudio.editor.flare.data.DataSet;
+	import gssim.gssimstudio.editor.flare.data.DataTable;
+	import gssim.gssimstudio.editor.flare.data.DataUtil;
+	
+	import flash.utils.ByteArray;
+	import flash.utils.IDataInput;
+	import flash.utils.IDataOutput;
+
+	/**
+	 * Converts data between delimited text (e.g., tab delimited) and
+	 * flare DataSet instances.
+	 */
+	public class DelimitedTextConverter implements IDataConverter
+	{
+		private var _delim:String;
+		
+		public function get delimiter():String { return _delim; }
+		public function set delimiter(d:String):void { _delim = d; }
+		
+		/**
+		 * Creates a new DelimitedTextConverter.
+		 * @param delim the delimiter string separating values (tab by default)
+		 */
+		public function DelimitedTextConverter(delim:String="\t")
+		{
+			_delim = delim;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public function read(input:IDataInput, schema:DataSchema=null):DataSet
+		{
+			return parse(input.readUTFBytes(input.bytesAvailable), schema);
+		}
+		
+		/**
+		 * Converts data from a tab-delimited string into ActionScript objects.
+		 * @param input the loaded input data
+		 * @param schema a data schema describing the structure of the data.
+		 *  Schemas are optional in many but not all cases.
+		 * @param data an array in which to write the converted data objects.
+		 *  If this value is null, a new array will be created.
+		 * @return an array of converted data objects. If the <code>data</code>
+		 *  argument is non-null, it is returned.
+		 */
+		public function parse(text:String, schema:DataSchema=null):DataSet
+		{
+			var tuples:Array = [];
+			var lines:Array = text.split(/\r\n|\r|\n/);
+			
+			if (schema == null) {
+				schema = inferSchema(lines);
+			}
+			
+			var i:int = schema.hasHeader ? 1 : 0;
+			for (; i<lines.length; ++i) {
+				var line:String = lines[i];
+				if (line.length == 0) break;
+				var tok:Array = line.split(_delim);
+				var tuple:Object = {};
+				for (var j:int=0; j<schema.numFields; ++j) {
+					var field:DataField = schema.getFieldAt(j);
+					tuple[field.name] = DataUtil.parseValue(tok[j], field.type);
+				}
+				tuples.push(tuple);
+			}
+			return new DataSet(new DataTable(tuples, schema));
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public function write(data:DataSet, output:IDataOutput=null):IDataOutput
+		{
+			if (output==null) output = new ByteArray();
+			var tuples:Array = data.nodes.data;
+			var schema:DataSchema = data.nodes.schema;
+			
+			for each (var tuple:Object in tuples) {
+				var i:int = 0, s:String;
+				if (schema == null) {
+					for (var name:String in tuple) {
+						if (i>0) output.writeUTFBytes(_delim);
+						output.writeUTFBytes(String(tuple[name])); // TODO: proper string formatting
+						++i;
+					}
+				} else {
+					for (;i<schema.numFields; ++i) {
+						var f:DataField = schema.getFieldAt(i);
+						if (i>0) output.writeUTFBytes(_delim);
+						output.writeUTFBytes(String(tuple[f.name])); // TODO proper string formatting
+					}
+				}
+				output.writeUTFBytes("\n");
+			}
+			return output;
+		}
+		
+		/**
+		 * Infers the data schema by checking values of the input data.
+		 * @param lines an array of lines of input text
+		 * @return the inferred schema
+		 */
+		protected function inferSchema(lines:Array):DataSchema
+		{
+			var header:Array = lines[0].split(_delim);
+			var types:Array = new Array(header.length);
+			
+			// initialize data types
+			var tok:Array = lines[1].split(_delim);
+			for (var col:int=0; col<header.length; ++col) {
+				types[col] = DataUtil.type(tok[col]);
+			}
+			
+			// now process data to infer types
+			for (var i:int = 2; i<lines.length; ++i) {
+				tok = lines[i].split(_delim);
+				for (col=0; col<tok.length; ++col) {
+					if (types[col] == -1) continue;
+					var type:int = DataUtil.type(tok[col]);
+					if (types[col] != type) {
+						types[col] = -1;
+					}
+				}
+			}
+			
+			// finally, we create the schema
+			var schema:DataSchema = new DataSchema();
+			schema.hasHeader = true;
+			for (col=0; col<header.length; ++col) {
+				schema.addField(new DataField(header[col],
+					types[col]==-1 ? DataUtil.STRING : types[col]));
+			}
+			return schema;
+		}
+		
+	} // end of class DelimitedTextConverter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSchema.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSchema.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSchema.as	(revision 15)
@@ -0,0 +1,81 @@
+package gssim.gssimstudio.editor.flare.data
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	
+	/**
+	 * A data schema represents a set of data variables and their associated 
+	 * types. A schema maintains a collection of <code>DataField</code>
+	 * objects.
+	 * @see flare.data.DataField
+	 */
+	public class DataSchema
+	{
+		public var dataRoot:String = null;
+		public var hasHeader:Boolean = false;
+		
+		private var _fields:/*DataField*/Array = [];
+		private var _nameLookup:/*String->DataField*/Object = {};
+		private var _idLookup:/*String->DataField*/Object = {};
+		
+		/** An array containing the data fields in this schema. */
+		public function get fields():Array { return Arrays.copy(_fields); }
+		/** The number of data fields in this schema. */
+		public function get numFields():int { return _fields.length; }
+		
+		/**
+		 * Creates a new DataSchema.
+		 * @param fields an ordered list of data fields to include in the
+		 * schema
+		 */
+		public function DataSchema(...fields)
+		{
+			for each (var f:DataField in fields) {
+				addField(f);
+			}
+		}
+		
+		/**
+		 * Adds a field to this schema.
+		 * @param field the data field to add
+		 */
+		public function addField(field:DataField):void
+		{
+			_fields.push(field);
+			_nameLookup[field.name] = field;
+			_idLookup[field.id] = field;
+		}
+		
+		/**
+		 * Retrieves a data field by name.
+		 * @param name the data field name
+		 * @return the corresponding data field, or null if no data field is
+		 *  found matching the name
+		 */
+		public function getFieldByName(name:String):DataField
+		{
+			return _nameLookup[name];
+		}
+		
+		/**
+		 * Retrieves a data field by id.
+		 * @param name the data field id
+		 * @return the corresponding data field, or null if no data field is
+		 *  found matching the id
+		 */
+		public function getFieldById(id:String):DataField
+		{
+			return _idLookup[id];
+		}
+		
+		/**
+		 * Retrieves a data field by its index in this schema.
+		 * @param idx the index of the data field in this schema
+		 * @return the corresponding data field
+		 */
+		public function getFieldAt(idx:int):DataField
+		{
+			return _fields[idx];
+		}
+		
+	} // end of class DataSchema
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSource.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSource.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataSource.as	(revision 15)
@@ -0,0 +1,90 @@
+package gssim.gssimstudio.editor.flare.data
+{
+	import flash.net.URLRequest;
+	import flash.net.URLStream;
+	import flash.utils.IDataInput;
+	import gssim.gssimstudio.editor.flare.data.converters.IDataConverter;
+	import flash.net.URLLoader;
+	import flash.events.Event;
+	import gssim.gssimstudio.editor.flare.data.converters.Converters;
+	import flash.utils.ByteArray;
+	import flash.net.URLLoaderDataFormat;
+	import flash.events.ProgressEvent;
+	
+	/**
+	 * A data source provides access to remote data on the Internet.
+	 * A DataSource requires a URL for retrieving a data file, and a format
+	 * string representing the data format. The currently supported formats are
+	 * "tab" (Tab-Delimited Text) and "json" (JavaScript Object Notation).
+	 * Additionally, a DataSource can be given a schema object describing the
+	 * data fields and their types (int, Number, Date, String, etc). If no
+	 * schema is provided, the data converter for the particular format will
+	 * attempt to infer the data types directly from the data itself.
+	 * 
+	 * <p>Once a DataSource has been created, use the <tt>load</tt> method to
+	 * initiate data loading. This method returns a <tt>URLLoader</tt> 
+	 * instance. Add a listener to the URLLoader's COMPLETE event to be
+	 * notified when loading and parsing has been completed. When a COMPLETE
+	 * event is issued, the URLLoader's <tt>data</tt> property will contain the
+	 * loaded and parsed data set.</p>
+	 */
+	public class DataSource
+	{
+		private var _url:String;
+		private var _format:String;
+		private var _schema:DataSchema;
+		
+		/** The URL of the remote data set. */
+		public function get url():String { return _url; }
+		/** The format of the remote data set (e.g., "tab" or "json"). */
+		public function get format():String { return _format; }
+		/** A schema describing the attributes of the data set. */
+		public function get schema():DataSchema { return _schema; }
+		
+		/**
+		 * Creates a new DataSource.
+		 * @param url the URL of the remote data set
+		 * @param format the format of the remote data set (e.g., "tab" or
+		 *  "json")
+		 * @param schema an optional schema describing the attibutes of the
+		 *  data set
+		 */
+		public function DataSource(url:String, format:String, schema:DataSchema=null)
+		{
+			_url = url;
+			_format = format;
+			_schema = schema;
+		}
+		
+		/**
+		 * Initiates loading of the data set. When the load completes, a data
+		 * converter instance is used to convert the retrieved data set into
+		 * ActionScript objects. The parsed data is then available through the
+		 * <code>data</code> property of the returned <code>URLLoader</code>.
+		 * @return a URLLoader instance responsible for loading the data set.
+		 *  Add an event listener for the <code>COMPLETE</code> event to be
+		 *  notified when data loading has completed.
+		 */
+		public function load():URLLoader
+		{
+			var loader:URLLoader = new URLLoader();
+			loader.dataFormat = URLLoaderDataFormat.BINARY;
+			loader.addEventListener(Event.COMPLETE,
+				function(evt:Event):void {
+					var conv:IDataConverter = Converters.lookup(_format);
+					loader.data = conv.read(loader.data, _schema);
+				}
+			);
+			loader.load(new URLRequest(_url));
+			return loader;
+		}
+		
+		/* TODO later -- support streaming data
+		public function stream():URLStream
+		{
+			
+		}
+		*/
+		
+	} // end of class DataSource
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataField.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataField.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataField.as	(revision 15)
@@ -0,0 +1,52 @@
+package gssim.gssimstudio.editor.flare.data
+{
+	/**
+	 * A data field stores metadata for an individual data variable.
+	 */
+	public class DataField
+	{
+		private var _id:String;
+		private var _name:String;
+		private var _format:String;
+		private var _label:String;
+		private var _type:int;
+		private var _def:Object;
+		
+		/** A unique id for the data field, often the name. */
+		public function get id():String { return _id; }
+		/** The name of the data field. */
+		public function get name():String { return _name; }
+		/** A formatting string for printing values of this field.
+		 *  @see flare.util.Stings#format
+		 */
+		public function get format():String { return _format; }
+		/** A label describing this data field, useful for axis titles. */
+		public function get label():String { return _label; }
+		/** The data type of this field.
+		 *  @see flare.data.DataUtil. */
+		public function get type():int { return _type; }
+		/** The default value for this data field. */
+		public function get defaultValue():Object { return _def; }
+		
+		/**
+		 * Creates a new DataField.
+		 * @param name the name of the data field
+		 * @param type the data type of this field
+		 * @param def the default value of this field
+		 * @param id a unique id for the field. If null, the name will be used
+		 * @param format a formatting string for printing values of this field
+		 * @param label a label describing this data field
+		 */
+		public function DataField(name:String, type:int, def:Object=null,
+		           id:String=null, format:String=null, label:String=null)
+		{
+			_name = name;
+			_type = type;
+			_def = def;
+			_id = (id==null ? name : id);
+			_format = format;
+			_label = label==null ? name : _label;
+		}
+		
+	} // end of class DataField
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataTable.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataTable.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/data/DataTable.as	(revision 15)
@@ -0,0 +1,27 @@
+package gssim.gssimstudio.editor.flare.data
+{
+	/**
+	 * A data table maintains a collection of data objects, each
+	 * representing a row of data, and an optional data schema describing
+	 * the data variables.
+	 */
+	public class DataTable
+	{
+		/**
+		 * Creates a new data table instance.
+		 * @param data an array of tuples, each tuple is a row of data
+		 * @param schema an optional DataSchema describing the data columns
+		 */
+		public function DataTable(data:Array, schema:DataSchema=null) {
+			this.data = data;
+			this.schema = schema;
+		}
+		
+		/** A DataSchema describing the data columns of the table. */
+		public var schema:DataSchema;
+		
+		/** An array of data objects, each representing a row of data. */
+		public var data:Array;
+		
+	} // end of class DataTable
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Displays.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Displays.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Displays.as	(revision 15)
@@ -0,0 +1,325 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	import flash.display.BitmapData;
+	import flash.display.DisplayObject;
+	import flash.display.DisplayObjectContainer;
+	import flash.events.Event;
+	import flash.geom.Matrix;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	import flash.utils.getDefinitionByName;
+	
+	/**
+	 * Utility methods for working with display objects. The methods include
+	 * support for panning, rotating, and zooming objects, generating thumbnail
+	 * images, traversing children lists, and adding stage listeners.
+	 */
+	public class Displays
+	{
+		private static var _point:Point = new Point();
+		
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function Displays()
+		{
+			throw new Error("This is an abstract class.");
+		}
+		
+		/**
+		 * Adds a listener to the stage via a given display object. If the
+		 * display object has already been added to the stage, the listener
+		 * will be added to the stage immediately. Otherwise, the listener will
+		 * be added whenever the display object is added to the stage. This
+		 * method allows you to add listeners for stage events without having
+		 * to explicitly manage the case where the defining elements have not
+		 * yet been added to the stage.
+		 * @param d the display object through which to access the stage
+		 * @param eventType the event type
+		 * @param listener the event listener
+		 * @param useCapture the event useCapture flag
+		 * @param priority the event listener priority
+		 * @param useWeakReference the event useWeakReference flag
+		 * @return the function that will add the listener to the stage upon
+		 *  an added to stage event, or null if the listener was directly
+		 *  added to the stage
+		 * @see flash.events.Event
+		 */
+		public static function addStageListener(d:DisplayObject,
+			eventType:String, listener:Function, useCapture:Boolean=false,
+			priority:Number=0, useWeakReference:Boolean=false):Function
+		{
+			if (d.stage) {
+				d.stage.addEventListener(eventType, listener, useCapture,
+					priority, useWeakReference);
+				return null;
+			} else {
+				var add:Function = function(e:Event=null):void
+				{
+					d.stage.addEventListener(eventType, listener,
+						useCapture, priority, useWeakReference);
+					d.removeEventListener(Event.ADDED_TO_STAGE, add);
+					d.stage.invalidate();
+				}
+				d.addEventListener(Event.ADDED_TO_STAGE, add);
+				return add;
+			}
+		}
+		
+		/**
+		 * Iterates over the children of the input display object container,
+		 * invoking a visitor function on each. If the visitor function returns
+		 * a Boolean true value, the iteration will stop with an early exit.
+		 * @param con the container to visit
+		 * @param visitor the visitor function to invoke on the children
+		 * @param filter an optional filter indicating which items should be
+		 *  visited
+		 * @param reverse optional flag indicating if the list should be
+		 *  visited in reverse order
+		 * @return true if the visitation was interrupted with an early exit
+		 */
+		public static function visitChildren(con:DisplayObjectContainer,
+			visitor:Function, filter:*=null, reverse:Boolean=false):Boolean
+		{
+			var i:uint, o:DisplayObject;
+			var f:Function = Filter.$(filter);
+			if (reverse)
+				for (i=con.numChildren; --i>=0; ) {
+					o = con.getChildAt(i);
+					if ((f==null || f(o)) && (visitor(o) as Boolean))
+						return true;
+				}
+			else
+				for (i=0; i<con.numChildren; ++i) {
+					o = con.getChildAt(i);
+					if ((f==null || f(o)) && (visitor(o) as Boolean))
+						return true;
+				}
+			return false;
+		}
+		
+		/**
+		 * Sorts the children of the given <code>DisplayObjectContainer</code>
+		 * using a comparator function.
+		 * @param d a display object container to sort. The sort may change the
+		 *  rendering order in which the contained display objects are drawn.
+		 * @param cmp a comparator <code>Function</code>.
+		 */
+		public static function sortChildren(
+			d:DisplayObjectContainer, cmp:Function):void
+		{
+			if (d==null) return;
+			var a:Array = new Array(d.numChildren);
+			for (var i:int=0; i<a.length; ++i) {
+				a[i] = d.getChildAt(i);
+			}
+			if (cmp==null) a.sort() else a.sort(cmp);
+			for (i=0; i<a.length; ++i) {
+				d.setChildIndex(a[i], i);
+			}
+		}
+		
+		/**
+		 * Sets property values on all children items. The values
+		 * within the <code>vals</code> argument can take a number of forms:
+		 * <ul>
+		 *  <li>If a value is a <code>Function</code>, it will be evaluated
+		 *      for each element and the result will be used as the property
+		 *      value for that element.</li>
+		 *  <li>If a value is an <code>IEvaluable</code> instance, such as
+		 *      <code>flare.util.Property</code> or
+		 *      <code>flare.query.Expression</code>, it will be evaluated for
+		 *      each element and the result will be used as the property value
+		 *      for that element.</li>
+		 *  <li>In all other cases, a property value will be treated as a
+		 *      literal and assigned for all elements.</li>
+		 * </ul>
+		 * @param d the container whose children's properties should be set.
+		 * @param vals an object containing the properties and values to set.
+		 * @param p an optional IValueProxy for collecting value updates.
+		 */
+		public static function setChildrenProperties(d:DisplayObjectContainer,
+			vals:Object, p:IValueProxy=null):void
+		{
+			if (p==null) p = Property.proxy;
+			var o:Object, i:uint;
+			
+			for (var name:String in vals) {
+				var value:* = vals[name];
+				var v:Function = value is Function ? value as Function
+					 : value is IEvaluable ? IEvaluable(value).eval : null;
+				
+				for (i=0; i<d.numChildren; ++i) {
+					o = d.getChildAt(i);
+					p.setValue(o, name, v!=null ? v(p.$(o)) : value);
+				}
+			}
+		}
+		
+		/**
+		 * Creates a thumbnail image of the input object using the (optional)
+		 * given size.  If no width, height, or bitmap data parameters are
+		 * provided then the natural size of the display object will be used.
+		 * If no width or height values are provided (i.e., they are less than
+		 * or equal to zero) but a bitmap data is provided, than the dimensions
+		 * of the bitmap data will be used. If all parameters are provided but
+		 * the width and height exceed the size of the bitmap data, then the
+		 * object will be drawn to match the provided width and height, but the
+		 * thumbnail will be clipped to the size of the bitmap data. If only
+		 * one of the width or height values are provided, than the other will
+		 * automatically be selected to preserve the original aspect ratio of
+		 * the object.
+		 * @param src the DisplayObject to create a thumbnail image of
+		 * @param width the desired width of the object in the thumbnail. If
+		 *  this value is less than or equal to zero it is ignored.
+		 * @param height the desired height of the object in the thumbnail If
+		 *  this value is less than or equal to zero it is ignored.
+		 * @param bd a BitmapData instance into which to draw the thumbnail.
+		 *  If no value is provided, a new BitmapData instance of the needed
+		 *  width and height will automatically be created.
+		 * @return the thumbnail image as a BitmapData instance
+		 */
+		public static function thumbnail(src:DisplayObject, width:Number=-1,
+			height:Number=-1, bd:BitmapData=null):BitmapData
+		{
+			try {
+				// make sure everything is rendered if DirtySprites exist
+				getDefinitionByName("flare.display.DirtySprite").renderDirty();
+			} catch (err:Error) { /* do nothing */ }
+			
+			var r:Rectangle = src.getBounds(src);
+			var hasW:Boolean = width>0, hasH:Boolean = height>0;
+			
+			// get thumbnail dimensions
+			if (hasW && !hasH) {
+				height = r.height * width / r.width;
+			} else if (!hasW && hasH) {
+				width = r.width * height / r.height;
+			} else {
+				width  = hasW ? width  : (bd ? bd.width  : r.width);
+				height = hasH ? height : (bd ? bd.height : r.height);
+			}
+			// create bitmap data as needed
+			bd = bd ? bd : new BitmapData(width, height, true, 0);
+			
+			// determine object transformation
+			var mat:Matrix = new Matrix();
+			mat.translate(-r.left, -r.top);
+			mat.scale(width/r.width, height/r.height);
+			
+			// draw the thumbnail and return
+			bd.draw(src, mat, src.transform.colorTransform, src.blendMode);
+			return bd;
+		}
+		
+		// -- Transformation Routines -----------------------------------------
+		
+		/**
+		 * Performs a pan (translation) on an input matrix.
+		 * The result is a transformation matrix including the translation.
+		 * @param mat an input transformation matrix
+		 * @param dx the change in x position
+		 * @param dy the change in y position
+		 * @return the resulting, panned transformation matrix
+		 */
+		public static function panMatrixBy(mat:Matrix, dx:Number, dy:Number):Matrix
+		{
+			mat.translate(dx, dy);
+			return mat;
+		}
+		
+		/**
+		 * Performs a zoom about a specific point on an input matrix.
+		 * The result is a transformation matrix including the zoom.
+		 * @param mat an input transformation matrix
+		 * @param scale a scale factor specifying the amount to zoom. A value
+		 *  of 2 will zoom in such that objects are twice as large. A value of
+		 *  0.5 will zoom out such that objects are half the size.
+		 * @param p the point about which to zoom in or out
+		 * @return the resulting, zoomed transformation matrix
+		 */
+		public static function zoomMatrixBy(mat:Matrix, scale:Number, p:Point):Matrix
+		{
+			mat.translate(-p.x, -p.y);
+			mat.scale(scale, scale);
+			mat.translate(p.x, p.y);
+			return mat;
+		}
+		
+		/**
+		 * Performs a rotation around a specific point on an input matrix.
+		 * The result is a transformation matrix including the rotation.
+		 * @param mat an input transformation matrix
+		 * @param angle the rotation angle, in degrees
+		 * @param p the point about which to zoom in or out
+		 * @return the resulting, rotated transformation matrix
+		 */
+		public static function rotateMatrixBy(mat:Matrix, angle:Number, p:Point):Matrix
+		{
+			mat.translate(-p.x, -p.y);
+			mat.rotate(angle * Math.PI/180);
+			mat.translate(p.x, p.y);
+			return mat;
+		}
+		
+		/**
+		 * Pan the "camera" by the specified amount.
+		 * @param obj the display object to treat as the camera
+		 * @param dx the change in x position, in the parent's coordinate space
+		 * @param dy the change in y position, in the parent's coordinate space
+		 * @param vp an optional value proxy (such as a
+		 *  <code>Transitioner</code>) for storing the new transform matrix
+		 */
+		public static function panBy(obj:DisplayObject, dx:Number, dy:Number,
+			vp:IValueProxy=null):void
+		{
+			var mat:Matrix = panMatrixBy(obj.transform.matrix, dx, dy);
+			if (vp==null) obj.transform.matrix = mat;
+			else vp.setValue(obj, "transform.matrix", mat);
+		}
+		
+		/**
+		 * Zoom the "camera" by the specified scale factor.
+		 * @param obj the display object to treat as the camera
+		 * @param scale a scale factor specifying the amount to zoom. A value
+		 *  of 2 will zoom in such that objects are twice as large. A value of
+		 *  0.5 will zoom out such that objects are half the size.
+		 * @param xp the x-coordinate around which to zoom, in stage
+		 *  coordinates. If this value is <code>NaN</code>, 0 will be used.
+		 * @param yp the y-coordinate around which to zoom, in stage
+		 *  coordinates. If this value is <code>NaN</code>, 0 will be used.
+		 * @param vp an optional value proxy (such as a
+		 *  <code>Transitioner</code>) for storing the new transform matrix
+		 */		
+		public static function zoomBy(obj:DisplayObject, scale:Number,
+			xp:Number=NaN, yp:Number=NaN, vp:IValueProxy=null):void
+		{
+			var p:Point = getLocalPoint(obj, xp, yp);
+			var mat:Matrix = zoomMatrixBy(obj.transform.matrix, scale, p);
+			if (vp==null) obj.transform.matrix = mat;
+			else vp.setValue(obj, "transform.matrix", mat);
+		}
+		
+		/**
+		 * Helper routine that maps points from stage coordinates to this
+		 * camera's parent's coordinate space. If either input value is NaN,
+		 * a value of zero is assumed.
+		 */
+		private static function getLocalPoint(obj:DisplayObject, xp:Number, yp:Number):Point
+		{
+			var xn:Boolean = isNaN(xp);
+			var yn:Boolean = isNaN(yp);
+			var p:Point = _point;
+			
+			if (!(xn && yn)) {
+				p.x = xp;
+				p.y = yp;
+				p = obj.parent.globalToLocal(p);
+			}
+			if (xn) p.x = 0;
+			if (yn) p.y = 0;
+			return p;
+		}
+
+	} // end of class Displays
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Strings.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Strings.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Strings.as	(revision 15)
@@ -0,0 +1,685 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	import flash.utils.ByteArray;
+	
+	/**
+	 * Utility methods for working with String instances. The
+	 * <code>format</code> method provides a powerful mechanism for formatting
+	 * and templating strings.
+	 */
+	public class Strings
+	{	
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function Strings() {
+			throw new Error("This is an abstract class.");
+		}
+		
+		/**
+		 * Creates a new string by repeating an input string.
+		 * @param s the string to repeat
+		 * @param reps the number of times to repeat the string
+		 * @return a new String containing the repeated input
+		 */
+		public static function repeat(s:String, reps:int):String
+		{
+			if (reps == 1) return s;
+			
+			var b:ByteArray = new ByteArray();
+			for (var i:uint=0; i<reps; ++i)
+				b.writeUTFBytes(s);
+			b.position = 0;
+			return b.readUTFBytes(b.length);
+		}
+		
+		/**
+		 * Aligns a string by inserting padding space characters as needed.
+		 * @param s the string to align
+		 * @param align an integer indicating both the desired length of
+		 *  the string (the absolute value of the input) and the alignment
+		 *  style (negative for left alignment, positive for right alignment)
+		 * @return the aligned string, padded or truncated as necessary
+		 */
+		public static function align(s:String, align:int):String
+		{
+			var left:Boolean = align < 0;
+			var len:int = left?-align:align, slen:int = s.length;
+			if (slen > len) {
+				return left ? s.substr(0,len) : s.substr(slen-len, len);
+			} else {
+				var pad:String = repeat(' ',len-slen);
+				return left ? s + pad : pad + s;
+			}
+		}
+		
+		/**
+		 * Pads a number with a specified number of "0" digits on
+		 * the left-hand-side of the number.
+		 * @param x an input number
+		 * @param digits the number of "0" digits to pad by
+		 * @return a padded string representation of the input number
+		 */
+		public static function pad(x:Number, digits:int):String
+		{
+			var neg:Boolean = (x < 0);
+			x = Math.abs(x);
+			var e:int = 1 + int(Math.log(x) / Math.LN10);
+			var s:String = String(x);
+			for (; e<digits; e++) { s = '0' + s; }
+			return neg ? "-"+s : s;
+		}
+		
+		/**
+		 * Pads a string with zeroes up to given length.
+		 * @param s the string to pad
+		 * @param n the target length of the padded string
+		 * @return the padded string. If the input string is already equal or
+		 *  longer than n characters it is returned unaltered. Otherwise, it
+		 *  is left-padded with zeroes up to form an n-character string.
+		 */
+		public static function padString(s:String, n:int):String
+		{
+			return (s.length < n ? repeat("0",n-s.length) + s : s);
+		}
+		
+		// --------------------------------------------------------------------
+
+		/** Default formatting string for numbers. */
+		public static const DEFAULT_NUMBER:String = "0.########";
+
+		private static const _BACKSLASH :Number = '\\'.charCodeAt(0);
+		private static const _LBRACE    :Number = '{'.charCodeAt(0);
+		private static const _RBRACE    :Number = '}'.charCodeAt(0);
+		private static const _QUOTE     :Number = '"'.charCodeAt(0);
+		private static const _APOSTROPHE:Number = '\''.charCodeAt(0);
+	
+		/**
+		 * Outputs a formatted string using a set of input arguments and string
+		 * formatting directives. This method uses the String formatting
+		 * conventions of the .NET framework, providing a very flexible system
+		 * for mapping input values into various string representations. For
+		 * examples and reference documentation for string formatting options,
+		 * see
+		 * <a href="http://blog.stevex.net/index.php/string-formatting-in-csharp/">
+		 * this example page</a> or
+		 * <a href="http://msdn2.microsoft.com/en-us/library/fbxft59x.aspx">
+		 * Microsoft's documentation</a>.
+		 * @param fmt a formatting string. Format strings include markup
+		 *  indicating where input arguments should be placed in the string,
+		 *  along with optional formatting directives. For example,
+		 *  <code>{1}, {0}</code> writes out the second value argument, a
+		 *  comma, and then the first value argument.
+		 * @param args value arguments to be placed within the formatting
+		 *  string.
+		 * @return the formatted string.
+		 */
+		public static function format(fmt:String, ...args):String
+		{
+			var b:ByteArray = new ByteArray(), a:Array;
+			var esc:Boolean = false, val:*;
+			var c:Number, idx:int, ialign:int;
+			var idx0:int, idx1:int, idx2:int;
+			var s:String, si:String, sa:String, sf:String;
+			
+			for (var i:uint=0; i<fmt.length; ++i) {
+				c = fmt.charCodeAt(i);
+				if (c == _BACKSLASH) {
+					// note escape char
+					if (esc) b.writeUTFBytes('\\');
+					esc = true;
+				}
+				else if (c == _LBRACE) {
+					// process pattern
+					if (esc) {
+						b.writeUTFBytes('{');
+						esc = false;
+					} else {
+						// get pattern boundary
+						idx = fmt.indexOf("}", i);
+						if (idx < 0)
+							throw new ArgumentError("Invalid format string.");
+						
+						// extract pattern
+						s = fmt.substring(i+1, idx);
+						
+						idx2 = s.indexOf(":");
+						idx1 = s.indexOf(",");
+						idx0 = Math.min(idx1<0 ? int.MAX_VALUE : idx1,
+										idx2<0 ? int.MAX_VALUE : idx2);
+						
+						si = idx0==int.MAX_VALUE ? s : s.substring(0,idx0);
+						sa = idx1<0 || idx1 > idx2 ? null : s.substring(idx1+1, idx2<0?s.length:idx2);
+						sf = idx2<0 ? null : s.substring(idx2+1);
+						
+						try {
+							if (sa != null) { ialign = int(sa); }
+							if ((idx0=uint(si))==0 && si!="0") {
+								val = Property.$(si).getValue(args[0]);
+							} else {
+								val = args[idx0];
+							}
+							pattern(b, sf, val);
+						} catch (x:*) {
+							throw new ArgumentError("Invalid format string.");
+						}
+						i = idx;
+					}
+				} else {
+					// by default, copy value to buffer
+					b.writeUTFBytes(fmt.charAt(i));
+				}
+			}
+			
+			b.position = 0;
+			s = b.readUTFBytes(b.length);
+			
+			// finally adjust string alignment as needed
+			return (sa != null ? align(s, ialign) : s);
+		}
+			
+		private static function pattern(b:ByteArray, pat:String, value:*):void
+		{
+			if (pat == null) {
+				b.writeUTFBytes(String(value));
+			} else if (value is Date) {
+				datePattern(b, pat, value as Date);
+			} else if (value is Number) {
+				numberPattern(b, pat, Number(value));
+			} else {
+				b.writeUTFBytes(String(value));
+			}
+		}
+		
+		private static function count(s:String, c:Number, i:int):int
+		{
+			var n:int = 0;
+			for (n=0; i<s.length && s.charCodeAt(i)==c; ++i, ++n) null;
+			return n;
+		}
+
+		// -- Date Formatting -------------------------------------------------
+
+		/** Array of full names for days of the week. */
+		public static var DAY_NAMES:Array =
+			["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+			 "Friday", "Saturday"];
+		/** Array of abbreviated names for days of the week. */
+		public static var DAY_ABBREVS:Array =
+			["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+		/** Array of full names for months of the year. */
+		public static var MONTH_NAMES:Array =
+			["January", "February", "March", "April", "May", "June",
+			 "July", "August", "September", "October", "November", "December"];
+		/** Array of abbreviated names for months of the year. */
+		public static var MONTH_ABBREVS:Array = 
+			["Jan", "Feb", "Mar", "Apr", "May", "Jun",
+			 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+		/** Abbreviated string indicating "PM" time. */
+		public static var PM1:String = "P";
+		/** Full string indicating "PM" time. */
+		public static var PM2:String = "PM";
+		/** Abbreviated string indicating "AM" time. */
+		public static var AM1:String = "A";
+		/** Full string indicating "AM" time. */
+		public static var AM2:String = "AM";
+		/** String indicating "AD" time. */
+		public static var AD:String = "AD";
+		/** String indicating "BC" time. */
+		public static var BC:String = "BC";		
+
+		private static const _DATE:Number = 'd'.charCodeAt(0);
+		private static const _FRAC:Number = 'f'.charCodeAt(0);
+		private static const _FRAZ:Number = 'F'.charCodeAt(0);
+		private static const _ERA :Number = 'g'.charCodeAt(0);
+		private static const _HOUR:Number = 'h'.charCodeAt(0);
+		private static const _HR24:Number = 'H'.charCodeAt(0);
+		private static const _MINS:Number = 'm'.charCodeAt(0);
+		private static const _MOS :Number = 'M'.charCodeAt(0);
+		private static const _SECS:Number = 's'.charCodeAt(0);
+		private static const _AMPM:Number = 't'.charCodeAt(0);
+		private static const _YEAR:Number = 'y'.charCodeAt(0);
+		private static const _ZONE:Number = 'z'.charCodeAt(0);
+
+		/**
+		 * Hashtable of standard formatting flags and their formatting patterns
+		 */
+		private static const _STD_DATE:Object = {
+			d: "MM/dd/yyyy",
+			D: "dddd, dd MMMM yyyy",
+			f: "dddd, dd MMMM yyyy HH:mm",
+			F: "dddd, dd MMMM yyyy HH:mm:ss",
+			g: "MM/dd/yyyy HH:mm",
+			G: "MM/dd/yyyy HH:mm:ss",
+			M: "MMMM dd",
+			m: "MMMM dd",
+			R: "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'",
+			r: "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'",
+			s: "yyyy-MM-ddTHH:mm:ss",
+			t: "HH:mm",
+			T: "HH:mm:ss",
+			u: "yyyy-MM-dd HH:mm:ssZ",
+			U: "yyyy-MM-dd HH:mm:ssZ", // must convert to UTC!
+			Y: "yyyy MMMM",
+			y: "yyyy MMMM"
+		};
+
+		private static function datePattern(b:ByteArray, p:String, d:Date):void
+		{
+			var a:int, i:int, j:int, n:int, c:Number, s:String;
+			
+			// check for standard format flag, retrieve pattern if needed
+			if (p.length == 1) {
+				if (p == "U") d = Dates.toUTC(d);
+				p = _STD_DATE[p];
+				if (p == null) throw new ArgumentError("Invalid date format: "+p);
+			}
+			
+			// process custom formatting pattern
+			for (i=0; i<p.length;) {
+				c = p.charCodeAt(i);
+				for (n=0,j=i; j<p.length && p.charCodeAt(j)==c; ++j, ++n) null;
+				
+				if (c == _DATE) {
+					if (n >= 4) {
+						b.writeUTFBytes(DAY_NAMES[d.day]);
+					} else if (n == 3) {
+						b.writeUTFBytes(DAY_ABBREVS[d.day]);
+					} else if (n == 2) {
+						b.writeUTFBytes(pad(d.date, 2));
+					} else {
+						b.writeUTFBytes(String(d.date));
+					}
+				}
+				else if (c == _ERA) {
+					b.writeUTFBytes(d.fullYear<0 ? BC : AD);
+				}
+				else if (c == _FRAC) {
+					a = int(Math.round(Math.pow(10,n) * (d.time/1000 % 1)));
+					b.writeUTFBytes(String(a));
+				}
+				else if (c == _FRAZ) {
+					a = int(Math.round(Math.pow(10,n) * (d.time/1000 % 1)));
+					s = String(a);
+					for (a=s.length; s.charCodeAt(a-1)==_ZERO; --a) null;
+					b.writeUTFBytes(s.substring(0,a));
+				}
+				else if (c == _HOUR) {
+					a = (a=(int(d.hours)%12)) == 0 ? 12 : a;
+					b.writeUTFBytes(n==2 ? pad(a,2) : String(a));
+				}
+				else if (c == _HR24) {
+					a = int(d.hours);
+					b.writeUTFBytes(n==2 ? pad(a,2) : String(a));
+				}
+				else if (c == _MINS) {
+					a = int(d.minutes);
+					b.writeUTFBytes(n==2 ? pad(a,2) : String(a));
+				}
+				else if (c == _MOS) {
+					if (n >= 4) {
+						b.writeUTFBytes(MONTH_NAMES[d.month]);
+					} else if (n == 3) {
+						b.writeUTFBytes(MONTH_ABBREVS[d.month]);
+					} else {
+						a = int(d.month+1);
+						b.writeUTFBytes(n==2 ? pad(a,2) : String(a));
+					}
+				}
+				else if (c == _SECS) {
+					a = int(d.seconds);
+					b.writeUTFBytes(n==2 ? pad(a,2) : String(a));
+				}
+				else if (c == _AMPM) {
+					s = d.hours > 11 ? (n==2 ? PM2 : PM1) : (n==2 ? AM2 : AM1);
+					b.writeUTFBytes(s);
+				}
+				else if (c == _YEAR) {
+					if (n == 1) {
+						b.writeUTFBytes(String(int(d.fullYear) % 100));
+					} else {
+						a = int(d.fullYear) % int(Math.pow(10,n));
+						b.writeUTFBytes(pad(a, n));
+					}
+				}
+				else if (c == _ZONE) {
+					c = int(d.timezoneOffset / 60);
+					if (c<0) { s='+'; c = -c; } else { s='-'; }
+					b.writeUTFBytes(s + (n>1 ? pad(c, 2) : String(c)));
+					if (n >= 3) {
+						b.position = b.length;
+						c = int(Math.abs(d.timezoneOffset) % 60);
+						b.writeUTFBytes(':'+pad(c,2));
+					}
+				}
+				else if (c == _BACKSLASH) {
+					b.writeUTFBytes(p.charAt(i+1));
+					n = 2;
+				}
+				else if (c == _APOSTROPHE) {
+					a = p.indexOf('\'',i+1);
+					b.writeUTFBytes(p.substring(i+1,a));
+					n = 1 + a - i;
+				}
+				else if (c == _QUOTE) {
+					a = p.indexOf('\"',i+1);
+					b.writeUTFBytes(p.substring(i+1,a));
+					n = 1 + a - i;
+				}
+				else if (c == _PERC) {
+					if (n>1) throw new ArgumentError("Invalid date format: "+p);
+				}
+				else {
+					b.writeUTFBytes(p.substr(i,n));
+				}
+				i += n;
+			}
+		}
+		
+		// -- Number Formatting -----------------------------------------------
+		
+		private static const GROUPING:String = ';';
+		private static const _ZERO:Number = '0'.charCodeAt(0);
+		private static const _HASH:Number = '#'.charCodeAt(0);
+		private static const _PERC:Number = '%'.charCodeAt(0);
+		private static const _DECP:Number = '.'.charCodeAt(0);
+		private static const _SEPR:Number = ','.charCodeAt(0);
+		private static const _PLUS:Number = '+'.charCodeAt(0);
+		private static const _MINUS:Number = '-'.charCodeAt(0);
+		private static const _e:Number = 'e'.charCodeAt(0);
+		private static const _E:Number = 'E'.charCodeAt(0);
+		
+		/** Separator for decimal (fractional) values. */
+		public static var DECIMAL_SEPARATOR:String = '.';
+		/** Separator for thousands values. */
+		public static var THOUSAND_SEPARATOR:String = ',';
+		/** String representing Not-a-Number (NaN). */
+		public static var NaN:String = 'NaN';
+		/** String representing positive infinity. */
+		public static var POSITIVE_INFINITY:String = "+Inf";
+		/** String representing negative infinity. */
+		public static var NEGATIVE_INFINITY:String = "-Inf";
+		
+		private static const _STD_NUM:Object = {
+			c: "$#,0.", // currency
+			d: "0", // integers
+			e: "0.00e+0", // scientific
+			f: 0, // fixed-point
+			g: 0, // general
+			n: "#,##0.", // number
+			p: "%", // percent
+			//r: 0, // round-trip
+			x: 0  // hexadecimal
+		};
+		
+		private static function numberPattern(b:ByteArray, p:String, x:Number):void
+		{
+			var idx0:int, idx1:int, s:String = p.charAt(0).toLowerCase();
+			var upper:Boolean = s.charCodeAt(0) != p.charCodeAt(0);
+			
+			if (isNaN(x)) {
+				// handle NaN
+				b.writeUTFBytes(Strings.NaN);
+			}
+			else if (!isFinite(x)) {
+				// handle infinite values
+				b.writeUTFBytes(x<0 ? NEGATIVE_INFINITY : POSITIVE_INFINITY);
+			}
+			else if (p.length <= 3 && _STD_NUM[s] != null) {
+				// handle standard formatting string
+				var digits:Number = p.length==1 ? 2 : int(p.substring(1));
+				
+				if (s == 'c') {
+					digits = p.length==1 ? 2 : digits;
+					if (digits == 0) {
+						numberPattern(b, _STD_NUM[s], x);
+					} else {
+						numberPattern(b, _STD_NUM[s]+"."+repeat("0",digits), x);
+					}
+				}
+				else if (s == 'd') {
+					b.writeUTFBytes(pad(Math.round(x), digits));
+				}
+				else if (s == 'e') {
+					s = x.toExponential(digits);
+					s = upper ? s.toUpperCase() : s.toLowerCase();
+					b.writeUTFBytes(s);
+				}
+				else if (s == 'f') {
+					b.writeUTFBytes(x.toFixed(digits));
+				}
+				else if (s == 'g') {
+					var exp:Number = Math.log(Math.abs(x)) / Math.LN10;
+					exp = (exp >= 0 ? int(exp) : int(exp-1));
+					digits = (p.length==1 ? 15 : digits);
+					if (exp < -4 || exp > digits) {
+						s = upper ? 'E' : 'e';
+						numberPattern(b, "0."+repeat("#",digits)+s+"+0", x);
+					} else {
+						numberPattern(b, "0."+repeat("#",digits), x);
+					}
+				}
+				else if (s == 'n') {
+					numberPattern(b, _STD_NUM[s]+repeat("0",digits), x);
+				}
+				else if (s == 'p') {
+					numberPattern(b, _STD_NUM[s], x);
+				}
+				else if (s == 'x') {
+					s = padString(x.toString(16), digits);
+					s = upper ? s.toUpperCase() : s.toLowerCase();
+					b.writeUTFBytes(s);
+				}
+				else {
+					throw new ArgumentError("Illegal standard format: "+p);
+				}
+			}
+			else {
+				// handle custom formatting string
+				// TODO: GROUPING designator is escaped or in string literal
+				// TODO: Error handling?
+				if ((idx0=p.indexOf(GROUPING)) >= 0) {
+					if (x > 0) {
+						p = p.substring(0, idx0);
+					} else if (x < 0) {
+						idx1 = p.indexOf(GROUPING, ++idx0);
+						if (idx1 < 0) idx1 = p.length;
+						p = p.substring(idx0, idx1);
+						x = -x;
+					} else {
+						idx1 = 1 + p.indexOf(GROUPING, ++idx0);
+						p = p.substring(idx1);
+					}
+				}
+				formatNumber(b, p, x);
+			}
+		}
+		
+		/**
+		 * 0: Zero placeholder
+		 * #: Digit placeholder
+		 * .: Decimal point (any duplicates are ignored)
+		 * ,: Thosand separator + scaling
+		 * %: Percentage placeholder
+		 * e/E: Scientific notation
+		 * 
+		 * if has comma before dec point, use grouping
+		 * if grouping right before dp, divide by 1000
+		 * if percent and no e, multiply by 100
+		 */
+		private static function formatNumber(b:ByteArray, p:String, x:Number):void
+		{
+			var i:int, j:int, c:Number, n:int=1, digit:int=0;
+			var pp:int=-1, dp:int=-1, ep:int=-1, ep2:int=-1, sp:int=-1;
+			var nd:int=0, nf:int=0, ne:int=0, max:int=p.length-1;
+			var xd:Number, xf:Number, xe:int=0, zd:int=0, zf:int=0;
+			var sd:String, sf:String, se:String;
+			var hash:Boolean = false;
+			
+			// ----------------------------------------------------------------
+			// first pass: extract info from the formatting pattern
+			
+			for (i=0; i<p.length; ++i) {
+				c = p.charCodeAt(i);
+				if (c == _ZERO || c == _HASH) {
+					if (dp == -1) {
+						if (nd==0) hash = true;
+						nd++;
+					} else nf++;
+				}
+				else if (c == _DECP) {
+					if (dp == -1) dp = i;
+				}
+				else if (c == _SEPR) {
+					if (sp == -1) sp = i;
+				}
+				else if (c == _PERC) {
+					if (pp == -1) pp = i;
+				}
+				else if (c == _e || c == _E) {
+					if (ep >= 0) continue;
+					ep = i;
+					if (i<max && (c=p.charCodeAt(i+1))==_PLUS || c==_MINUS) ++i;
+					for (;i<max && p.charCodeAt(i+1)==_ZERO; ++i, ++ne) null;
+					ep2 = i;
+					if (p.charCodeAt(ep2) != _ZERO) { ep = ep2 = -1; ne=0; }
+				}
+				else if (c == _BACKSLASH) {
+					++i;
+				}
+				else if (c == _APOSTROPHE) {
+					// skip string literal
+					for(i=i+1; i<p.length && (c==_BACKSLASH || (c=p.charCodeAt(i))!=_APOSTROPHE); ++i) null;
+				}
+				else if (c == _QUOTE) {
+					// skip string literal
+					for(i=i+1; i<p.length && (c==_BACKSLASH || (c=p.charCodeAt(i))!=_QUOTE); ++i) null;
+				}
+			}
+			
+			
+			// ----------------------------------------------------------------
+			// extract information for second pass
+			
+			// process grouping separators and thousands scaling
+			var group:Boolean = false, adj:Boolean = true;
+			if (sp >= 0) {
+				if (dp >= 0) {
+					i = dp;
+				} else {
+					i = p.length;
+					while (i>sp) {
+						c = p.charCodeAt(i-1);
+						if (c==_ZERO || c==_HASH || c==_SEPR) break;
+						--i;
+					}
+				}
+				for (; --i >= sp;) {
+					if (p.charCodeAt(i) == _SEPR) {
+						if (adj) { x /= 1000; } else { group = true; break; }
+					} else {
+						adj = false;
+					}
+				}
+			}
+			// process percentage
+			if (pp >= 0) {
+				x *= 100;
+			}
+			// process negative number
+			if (x < 0) {
+				b.writeUTFBytes('-');
+				x = Math.abs(x);
+			}
+			// process power of ten for scientific format
+			if (ep >= 0) {
+				c = Math.log(x) / Math.LN10;
+				xe = (c>=0 ? int(c) : int(c-1)) - (nd-1);
+				x = x / Math.pow(10, xe);
+			}
+			// round the number as needed
+			c = Math.pow(10, nf);
+			x = Math.round(c*x) / c;
+			// separate number into component parts
+			xd = nf > 0 ? Math.floor(x) : Math.round(x);
+			xf = x - xd;
+			// create strings for integral and fractional parts
+			sd = pad(xd, nd);
+			sf = (xf+1).toFixed(nf).substring(2); // add 1 to avoid AS3 bug
+			if (hash) for (; zd<sd.length && sd.charCodeAt(zd)==_ZERO; ++zd) null;
+			for (zf=sf.length; --zf>=0 && sf.charCodeAt(zf)==_ZERO;) null;
+			
+			
+			// ----------------------------------------------------------------
+			// second pass: format the number
+			
+			var inFraction:Boolean = false;
+			for (i=0, n=0; i<p.length; ++i) {
+				c = p.charCodeAt(i);
+				if (i == dp) {
+					if (zf >= 0 || p.charCodeAt(i+1) != _HASH)
+						b.writeUTFBytes(DECIMAL_SEPARATOR);
+					inFraction = true;
+					n = 0;
+				}
+				else if (i == ep) {
+					b.writeUTFBytes(p.charAt(i));
+					if ((c=p.charCodeAt(i+1)) == _PLUS && xe > 0)
+						b.writeUTFBytes('+');
+					b.writeUTFBytes(pad(xe, ne));
+					i = ep2;
+				}
+				else if (!inFraction && n==0 && (c==_HASH || c==_ZERO)
+						 && sd.length-zd > nd) {
+					if (group) {
+						for (n=zd; n<=sd.length-nd; ++n) {
+							b.writeUTFBytes(sd.charAt(n));
+							if ((j=(sd.length-n-1)) > 0 && j%3 == 0)
+								b.writeUTFBytes(THOUSAND_SEPARATOR);
+						}	
+					} else {
+						n = sd.length - nd + 1;
+						b.writeUTFBytes(sd.substr(zd, n-zd));
+					}
+				}
+				else if (c == _HASH) {
+					if (inFraction) {
+						if (n <= zf) b.writeUTFBytes(sf.charAt(n));
+					} else if (n >= zd) {
+						b.writeUTFBytes(sd.charAt(n));
+						if (group && (j=(sd.length-n-1)) > 0 && j%3 == 0)
+							b.writeUTFBytes(THOUSAND_SEPARATOR);
+					}
+					++n;
+				}
+				else if (c == _ZERO) {
+					if (inFraction) {
+						b.writeUTFBytes(n>=sf.length ? '0' : sf.charAt(n));
+					} else {
+						b.writeUTFBytes(sd.charAt(n));
+						if (group && (j=(sd.length-n-1)) > 0 && j%3 == 0)
+							b.writeUTFBytes(THOUSAND_SEPARATOR);
+					}
+					++n;
+				}
+				else if (c == _BACKSLASH) {
+					b.writeUTFBytes(p.charAt(++i));
+				}
+				else if (c == _APOSTROPHE) {
+					for(j=i+1; j<p.length && (c==_BACKSLASH || (c=p.charCodeAt(j))!=_APOSTROPHE); ++j) null;
+					if (j-i > 1) b.writeUTFBytes(p.substring(i+1,j));
+					i=j;
+				}
+				else if (c == _QUOTE) {
+					for(j=i+1; j<p.length && (c==_BACKSLASH || (c=p.charCodeAt(j))!=_QUOTE); ++j) null;
+					if (j-i > 1) b.writeUTFBytes(p.substring(i+1,j));
+					i=j;
+				}
+				else {
+					if (c != _DECP && c != _SEPR) b.writeUTFBytes(p.charAt(i));
+				}
+			}
+		}
+		
+	} // end of class Strings
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Orientation.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Orientation.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Orientation.as	(revision 15)
@@ -0,0 +1,45 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	/**
+	 * Constants defining layout orientations.
+	 */
+	public class Orientation
+	{
+		/** Constant indicating a left-to-right layout orientation. */
+		public static const LEFT_TO_RIGHT:String = "leftToRight";
+		/** Constant indicating a right-to-left layout orientation. */
+		public static const RIGHT_TO_LEFT:String = "rightToLeft";
+		/** Constant indicating a top-to-bottom layout orientation. */
+		public static const TOP_TO_BOTTOM:String = "topToBottom";
+		/** Constant indicating a bottom-to-top layout orientation. */
+		public static const BOTTOM_TO_TOP:String = "bottomToTop";
+		
+		/**
+		 * This is an abstract class and can not be instantiated.
+		 */
+		public function Orientation() {
+			throw new Error("This is an abstract class.");
+		}
+
+		/**
+		 * Returns true if the input string indicates a vertical orientation.
+		 * @param an orientation string
+		 * @return true if the input string indicates a vertical orientation
+		 */
+		public static function isVertical(orient:String):Boolean
+		{
+			return (orient==TOP_TO_BOTTOM || orient==BOTTOM_TO_TOP);
+		}
+		
+		/**
+		 * Returns true if the input string indicates a horizontal orientation.
+		 * @param an orientation string
+		 * @return true if the input string indicates a horizontal orientation
+		 */
+		public static function isHorizontal(orient:String):Boolean
+		{
+			return (orient==LEFT_TO_RIGHT || orient==RIGHT_TO_LEFT);
+		}
+
+	} // end of class Orientation
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Geometry.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Geometry.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Geometry.as	(revision 15)
@@ -0,0 +1,275 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Utility methods for computational geometry.
+	 */
+	public final class Geometry
+	{		
+        /**
+         * Computes the co-efficients for a cubic Bezier curve.
+         * @param a the starting point of the curve
+         * @param b the first control point of the curve
+         * @param c the second control point of the curve
+         * @param d the ending point of the curve
+         * @param c1 point in which to store the zero-order co-efficients
+         * @param c2 point in which to store the first-order co-efficients
+         * @param c3 point in which to store the second-order co-efficients
+         */
+        public static function cubicCoeff(a:Point, b:Point, c:Point, d:Point,
+        								  c1:Point, c2:Point, c3:Point) : void
+        {            
+            c3.x = 3 * (b.x - a.x);
+            c2.x = 3 * (c.x - b.x) - c3.x;
+            c1.x = d.x - a.x - c3.x - c2.x;
+            
+            c3.y = 3 * (b.y - a.y);
+            c2.y = 3 * (c.y - b.y) - c3.y;
+            c1.y = d.y - a.y - c3.y - c2.y;
+        }
+        
+        /**
+         * Computes a point along a cubic Bezier curve.
+         * @param u the interpolation fraction along the curve (between 0 and 1)
+         * @param a the starting point of the curve
+		 * @param c1 the zero-order Bezier co-efficients
+         * @param c2 the first-order Bezier co-efficients
+         * @param c3 the second-order Bezier co-efficients
+         * @param p point in which to store the calculated point on the curve
+         */
+        public static function cubic(u:Number, a:Point, 
+        							 c1:Point, c2:Point, c3:Point,
+        						     p:Point) : Point
+        {
+            p.x = u*(c3.x + u*(c2.x + u*c1.x)) + a.x;
+			p.y = u*(c3.y + u*(c2.y + u*c1.y)) + a.y;
+            return p;
+        }
+        
+        /**
+         * Computes the co-efficients for a B-spline.
+         * @param p the control points of the spline as an array of x,y values
+         * @param a an array for storing the x-components of co-efficients
+         * @param b an array for storing the y-components of co-efficients
+         */
+        public static function bsplineCoeff(p:Array, a:Array, b:Array):void
+        {
+        	a[0] = (-p[0] + 3 * p[2] - 3 * p[4] + p[6]) / 6.0;
+        	a[1] = (3 * p[0] - 6 * p[2] + 3 * p[4]) / 6.0;
+			a[2] = (-3 * p[0] + 3 * p[4]) / 6.0;
+			a[3] = (p[0] + 4 * p[3] + p[4]) / 6.0;
+			
+			b[0] = (-p[1] + 3 * p[3] - 3 * p[5] + p[7]) / 6.0;
+        	b[1] = (3 * p[1] - 6 * p[3] + 3 * p[5]) / 6.0;
+			b[2] = (-3 * p[1] + 3 * p[5]) / 6.0;
+			b[3] = (p[1] + 4 * p[4] + p[5]) / 6.0;
+        }
+        
+        /**
+         * Computes a point along a B-spline.
+         * @param u the interpolation fraction along the curve (between 0 and 1)
+         * @param a an array of x-components of the B-spline co-efficients
+         * @param b an array of y-components of the B-spline co-efficients
+         * @param s point in which to store the calculated point on the curve
+         */
+        public static function bspline(u:Number, a:Array, b:Array, s:Point) : Point
+        {
+			s.x = u*(a[2] + u*(a[1] + u*a[0])) + a[3];
+			s.y = u*(b[2] + u*(b[1] + u*b[0])) + b[3];
+			return s;
+		}
+
+		// --------------------------------------------------------------------
+		
+		/** Indicates no intersection between shapes */
+    	public static const NO_INTERSECTION:int = 0;
+    	/** Indicates intersection between shapes */
+    	public static const COINCIDENT:int      = -1;
+    	/** Indicates two lines are parallel */
+    	public static const PARALLEL:int        = -2;
+		
+		/**
+	     * Compute the intersection of two line segments.
+	     * @param a1x the x-coordinate of the 1st endpoint of the 1st line
+	     * @param a1y the y-coordinate of the 1st endpoint of the 1st line
+	     * @param a2x the x-coordinate of the 2nd endpoint of the 1st line
+	     * @param a2y the y-coordinate of the 2nd endpoint of the 1st line
+	     * @param b1x the x-coordinate of the 1st endpoint of the 2nd line
+	     * @param b1y the y-coordinate of the 1st endpoint of the 2nd line
+	     * @param b2x the x-coordinate of the 2nd endpoint of the 2nd line
+	     * @param b2y the y-coordinate of the 2nd endpoint of the 2nd line
+	     * @param intersect a Point in which to store the intersection point
+	     * @return the intersection code. This is either the number of
+	     *  intersections or one of {@link #NO_INTERSECTION},
+	     *  {@link #COINCIDENT}, or {@link #PARALLEL}.
+	     */
+	    public static function intersectLines(a1x:Number, a1y:Number,
+	    	a2x:Number, a2y:Number, b1x:Number, b1y:Number, b2x:Number,
+	    	b2y:Number, intersect:Point):int
+	    {
+	        var ua_t:Number = (b2x-b1x)*(a1y-b1y)-(b2y-b1y)*(a1x-b1x);
+	        var ub_t:Number = (a2x-a1x)*(a1y-b1y)-(a2y-a1y)*(a1x-b1x);
+	        var u_b :Number = (b2y-b1y)*(a2x-a1x)-(b2x-b1x)*(a2y-a1y);
+	
+	        if (u_b != 0) {
+	            var ua:Number = ua_t / u_b;
+	            var ub:Number = ub_t / u_b;
+	
+	            if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {
+	            	intersect.x = a1x+ua*(a2x-a1x);
+	            	intersect.y = a1y+ua*(a2y-a1y);
+	                return 1;
+	            } else {
+	                return NO_INTERSECTION;
+	            }
+	        } else {
+	            return (ua_t == 0 || ub_t == 0 ? COINCIDENT : PARALLEL);
+	        }
+	    }
+		
+		/**
+	     * Compute the intersection of a line and a rectangle.
+	     * @param a1 the first endpoint of the line
+	     * @param a2 the second endpoint of the line
+	     * @param r the rectangle
+	     * @param pts a length 2 or greater array of points in which to store
+	     * the results 
+	     * @return the intersection code. This is either the number of
+	     *  intersections or one of {@link #NO_INTERSECTION},
+	     *  {@link #COINCIDENT}, or {@link #PARALLEL}.
+	     */
+	    public static function intersectLineRect(a1x:Number, a1y:Number,
+	    	a2x:Number, a2y:Number, r:Rectangle, p0:Point, p1:Point):int
+	    {
+	        var xMax:Number = r.right, yMax:Number = r.bottom;
+	        var xMin:Number = r.left,  yMin:Number = r.top;
+	        
+	        var i:int = 0, p:Point = p0;
+	        if (intersectLines(xMin,yMin,xMax,yMin, a1x,a1y,a2x,a2y, p) > 0) {
+	        	++i; p = p1;
+	        }
+	        if (intersectLines(xMax,yMin,xMax,yMax, a1x,a1y,a2x,a2y, p) > 0) {
+	        	++i; p = p1;
+	        }
+	        if (i == 2) return i;
+	        if (intersectLines(xMax,yMax,xMin,yMax, a1x,a1y,a2x,a2y, p) > 0) {
+	        	++i; p = p1;
+	        }
+	        if (i == 2) return i;
+	        if (intersectLines(xMin,yMax,xMin,yMin, a1x,a1y,a2x,a2y, p) > 0) {
+	        	++i; p = p1;
+	        }
+	        return i;
+	    }
+
+        /**
+         * Computes the convex hull for a set of points.
+         * @param p the input points, as a flat array of x,y values
+         * @param len the number of points to include in the hull
+         * @return the convex hull, as a flat array of x,y values
+         */
+        public static function convexHull(p:Array, len:uint) : Array
+        {
+        	// check arguments
+            if (len < 3)
+            	throw new ArgumentError('Input must have at least 3 points');
+            
+            var pts:Array = new Array(len-1);
+            var stack:Array = new Array(len);
+			var i:uint, j:uint, i0:uint = 0;
+
+            // find the starting ref point: leftmost point with the minimum y coord
+            for (i = 0; i < len; ++i)
+            {
+                if (p[i].Y < p[i0].Y) { 
+                	i0 = i;
+                } else if (p[i].Y == p[i0].Y) {
+                	i0 = (p[i].X < p[i0].X ? i : i0);
+                }
+            }
+
+            // calculate polar angles from ref point and sort
+            for (i = 0, j = 0; i < len; ++i) {
+                if (i != i0) {
+                	pts[j++] = {
+                		angle: Math.atan2(p[i].Y-p[i0].Y, p[i].X-p[i0].X),
+                		index: i
+                	};
+                }
+            }
+            pts.sortOn('angle');
+
+            // toss out duplicated angles
+            var angle:Number = pts[0].angle;
+            var ti:uint = 0, tj:uint = pts[0].index;
+            for (i = 1; i < len-1; i++) {
+                j = pts[i].index;
+                if (angle == pts[i].angle)
+                {
+                    // keep angle corresponding to point most distant from reference point
+                    var d1:Number = Point.distance(p[i0], p[tj]);
+                    var d2:Number = Point.distance(p[i0], p[j]);
+                    
+                    if (d1 >= d2) {
+                        pts[i].index = -1;
+                    } else {
+                        pts[ti].index = -1;
+                        angle = pts[i].angle;
+                        ti = i;
+                        tj = j;
+                    }
+                } else {
+                    angle = pts[i].angle;
+                    ti = i;
+                    tj = j;
+                }
+            }
+
+            // initialize the stack
+            var sp:uint = 0;
+            stack[sp++] = i0;
+            var h:uint = 0;
+            for (var k:uint = 0; k < 2; h++) {
+                if (pts[h].index != -1) {
+                    stack[sp++] = pts[h].index;
+                    k++;
+                }
+            }
+
+            // do graham's scan
+            for (; h < len-1; h++)
+            {
+                if (pts[h].index == -1) continue; // skip tossed out points
+                while (isNonLeft(i0, stack[sp-2], stack[sp-1], pts[h].index, p))
+                    sp--;
+                stack[sp++] = pts[h].index;
+            }
+
+            // construct the hull
+            var hull:Array = new Array(sp);
+            for (i = 0; i < sp; ++i) {
+                hull[i] = p[stack[i]];
+            }
+            return hull;
+        }
+
+        private static function isNonLeft(i0:uint, i1:uint, i2:uint, i3:uint, p:Array) : Boolean
+        {
+            var l1:Number, l2:Number, l4:Number, l5:Number, l6:Number, a:Number, b:Number;
+
+            a = p[i2].y - p[i1].y; b = p[i2].x - p[i1].y; l1 = Math.sqrt(a * a + b * b);
+            a = p[i3].y - p[i2].y; b = p[i3].x - p[i2].y; l2 = Math.sqrt(a * a + b * b);
+            a = p[i3].y - p[i0].y; b = p[i3].x - p[i0].y; l4 = Math.sqrt(a * a + b * b);
+            a = p[i1].y - p[i0].y; b = p[i1].x - p[i0].y; l5 = Math.sqrt(a * a + b * b);
+            a = p[i2].y - p[i0].y; b = p[i2].x - p[i0].y; l6 = Math.sqrt(a * a + b * b);
+            
+            a = Math.acos((l2*l2 + l6*l6 - l4*l4) / (2*l2*l6));
+            b = Math.acos((l6*l6 + l1*l1 - l5*l5) / (2*l6*l1));
+
+            return (Math.PI - a - b < 0);
+        }
+		
+	} // end of class Geometry
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/Palette.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/Palette.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/Palette.as	(revision 15)
@@ -0,0 +1,42 @@
+package gssim.gssimstudio.editor.flare.util.palette
+{
+	import mx.core.IMXMLObject;
+	
+	/**
+	 * Base class for palettes, such as color and size palettes, that map from
+	 * interpolated scale values into visual properties
+	 */
+	public class Palette implements IMXMLObject
+	{
+		/** Array of palette values. */
+		protected var _values:Array;
+		
+		/** The number of values in the palette. */
+		public function get size():int { return _values==null ? 0 : _values.length; }
+		/** Array of palette values. */
+		public function get values():Array { return _values; }
+		public function set values(a:Array):void { _values = a; }
+		
+		/**
+		 * Retrieves the palette value corresponding to the input interpolation
+		 * fraction.
+		 * @param f an interpolation fraction
+		 * @return the palette value corresponding to the input fraction
+		 */
+		public function getValue(f:Number):Object
+		{
+			if (_values==null || _values.length==0)
+				return 0;
+			return _values[uint(Math.round(f*(_values.length-1)))];
+		}
+		
+		// -- MXML ------------------------------------------------------------
+		
+		/** @private */
+		public function initialized(document:Object, id:String):void
+		{
+			// do nothing
+		}
+		
+	} // end of class Palette
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/ShapePalette.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/ShapePalette.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/ShapePalette.as	(revision 15)
@@ -0,0 +1,75 @@
+package gssim.gssimstudio.editor.flare.util.palette
+{
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	
+	/**
+	 * Palette for shape values that maps integer indices to shape drawing
+	 * functions.
+	 * @see flare.vis.util.graphics.Shapes
+	 */
+	public class ShapePalette extends Palette
+	{	
+		/**
+		 * Creates a new, empty ShapePalette.
+		 */
+		public function ShapePalette() {
+			_values = new Array();
+		}	
+		
+		/**
+		 * Adds a shape to this ShapePalette.
+		 * @param shape the name of the shape. This name should be registered
+		 *  with a drawing function using the
+		 *  <code>flare.vis.util.graphics.Shapes</code> class.
+		 */
+		public function addShape(shape:String):void
+		{
+			_values.push(shape);
+		}
+		
+		/**
+		 * Gets the shape at the given index into the palette.
+		 * @param idx the index of the shape
+		 * @return the name of the shape
+		 */
+		public function getShape(idx:uint):String
+		{
+			return _values[idx % _values.length];
+		}
+		
+		/**
+		 * Sets the shape at the given index into the palette.
+		 * @param idx the index of the shape
+		 * @param shape the name of the shape. This name should be registered
+		 *  with a drawing function using the
+		 *  <code>flare.vis.util.graphics.Shapes</code> class.
+		 */
+		public function setShape(idx:uint, shape:String):void
+		{
+			_values[idx] = shape;
+		}
+		
+		/**
+		 * Returns a default shape palette instance. The default palette
+		 * consists of (in order): circle, square, cross, "x", diamond,
+		 * down-triangle, up-triangle, left-triangle, and right-triangle
+		 * shapes.
+		 * @return the default shape palette
+		 */
+		public static function defaultPalette():ShapePalette
+		{
+			var p:ShapePalette = new ShapePalette();
+			p.addShape(Shapes.CIRCLE);
+			p.addShape(Shapes.SQUARE);
+			p.addShape(Shapes.CROSS);
+			p.addShape(Shapes.X);
+			p.addShape(Shapes.DIAMOND);
+			p.addShape(Shapes.TRIANGLE_DOWN);
+			p.addShape(Shapes.TRIANGLE_UP);
+			p.addShape(Shapes.TRIANGLE_LEFT);
+			p.addShape(Shapes.TRIANGLE_RIGHT);
+			return p;
+		}
+		
+	} // end of class ShapePalette
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/SizePalette.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/SizePalette.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/SizePalette.as	(revision 15)
@@ -0,0 +1,70 @@
+package gssim.gssimstudio.editor.flare.util.palette
+{
+	/**
+	 * Palette for size values represeneted as scale factors. The SizePalette
+	 * class distinguishes between 1D and 2D scale factors, with a square
+	 * root being applied to 2D scale factors to ensure that area scales
+	 * linearly with the size value.
+	 */
+	public class SizePalette extends Palette
+	{
+		private var _minSize:Number = 1;
+		private var _range:Number = 6;
+		private var _is2D:Boolean = true;
+		
+		/** The minimum scale factor in this size palette. */
+		public function get minimumSize():Number { return _minSize; }
+		public function set minimumSize(s:Number):void {
+			_range += s - _minSize; _minSize = s;
+		}
+		
+		/** the maximum scale factor in this size palette. */
+		public function get maximumSize():Number { return _minSize + _range; }
+		public function set maximumSize(s:Number):void { _range = s - _minSize; }
+		
+		/** Flag indicating if this size palette is for 2D shapes. */
+		public function get is2D():Boolean { return _is2D; }
+		public function set is2D(b:Boolean):void { _is2D = b; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new SizePalette.
+		 * @param minSize the minimum scale factor in the palette
+		 * @param maxSize the maximum scale factor in the palette
+		 * @param is2D flag indicating if the size values are for a 2D shape,
+		 *  true by default
+		 */		
+		public function SizePalette(minSize:Number=1, maxSize:Number=6, is2D:Boolean=true)
+		{
+			_minSize = minSize;
+			_range = maxSize - minSize;
+			_is2D = is2D;
+		}
+		
+		/** @inheritDoc */
+		public override function getValue(f:Number):Object
+		{
+			return getSize(f);
+		}
+		
+		/**
+		 * Retrieves the size value corresponding to the input interpolation
+		 * fraction. If the <code>is2D</code> flag is true, the square root
+		 * of the size value is returned.
+		 * @param f an interpolation fraction
+		 * @return the size value corresponding to the input fraction
+		 */
+		public function getSize(v:Number):Number
+		{
+			var s:Number;
+			if (_values == null) {
+				s = _minSize + v * _range;
+			} else {
+				s = _values[uint(Math.round(v*(_values.length-1)))];
+			}
+			return _is2D ? Math.sqrt(s) : s;
+		}
+		
+	} // end of class SizePalette
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/ColorPalette.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/ColorPalette.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/palette/ColorPalette.as	(revision 15)
@@ -0,0 +1,177 @@
+package gssim.gssimstudio.editor.flare.util.palette
+{
+	import gssim.gssimstudio.editor.flare.util.Colors;
+	
+	/**
+	 * Palette for color values, including utility methods for generating
+	 * both categorical and ordinal color palettes.
+	 */
+	public class ColorPalette extends Palette
+	{
+		private var _keyframes:Array;
+		
+		/** Keyframes at which color values change in the palette. Useful
+		 *  for configuring gradient paint fills. */
+		public function get keyframes():Array { return _keyframes; }
+		
+		/**
+		 * Creates a new ColorPalette.
+		 * @param colors an array of colors defining the palette
+		 * @param keyframes array of keyframes of color interpolations
+		 */
+		public function ColorPalette(colors:Array=null, keyframes:Array=null) {
+			_values = colors;
+			_keyframes = keyframes;
+		}
+		
+		/**
+		 * Retrieves the color corresponding to input interpolation fraction.
+		 * @param f an interpolation fraction
+		 * @return the color corresponding to the input fraction
+		 */
+		public function getColor(v:Number):uint
+		{
+			if (_values==null || _values.length==0)
+				return 0;
+			return _values[uint(Math.round(v*(_values.length-1)))];
+		}
+		
+		/**
+		 * Retrieves the color corresponding to the input array index.
+		 * @param idx an integer index. The actual index value used is
+		 *  the modulo of the input index by the length of the palette.
+		 * @return the color in the palette at the given index
+		 */
+		public function getColorByIndex(idx:int):uint
+		{
+			if (_values == null || _values.length == 0 || idx < 0)
+				return 0;
+			else
+				return _values[idx % _values.length];
+		}
+		
+		// --------------------------------------------------------------------
+				
+		/** Default size of generated color palettes. */
+		public static const DEFAULT_SIZE:int = 64;
+		/** A set of 10 colors for encoding category values. */
+		public static const CATEGORY_COLORS_10:/*uint*/Array = [
+			0xFF1F77B4, 0xFFFF7F0E, 0xFF2CA02C, 0xFFD62728, 0xFF9467BD,
+			0xFF8C564B, 0xFFE377C2, 0xFF7F7F7F, 0xFFBCBD22, 0xFF17BECF
+		];
+		/** A set of 20 colors for encoding category values. Includes
+		 *  the colors of <code>CATEGORY_COLORS_10</code> plus lighter
+		 *  shades of each. */
+		public static const CATEGORY_COLORS_20:/*uint*/Array = [
+			0xFF1F77B4, 0xFFAEC7E8, 0xFFFF7F0E, 0xFFFFBB78, 0xFF2CA02C,
+			0xFF98DF8A, 0xFFD62728, 0xFFFF9896, 0xFF9467BD, 0xFFC5B0D5,
+			0xFF8C564B, 0xFFC49C94, 0xFFE377C2, 0xFFF7B6D2, 0xFF7F7F7F,
+			0xFFC7C7C7, 0xFFBCBD22, 0xFFDBDB8D, 0xFF17BECF, 0xFF9EDAE5
+		];
+		/** An alternative set of 19 colors for encoding category values. */
+		public static const CATEGORY_COLORS_ALT_19:/*uint*/Array = [
+			0xff9C9EDE, 0xff7375B5, 0xff4A5584, 0xffCEDB9C, 0xffB5CF6B,
+			0xff8CA252, 0xff637939, 0xffE7CB94, 0xffE7BA52, 0xffBD9E39,
+			0xff8C6D31, 0xffE7969C, 0xffD6616B, 0xffAD494A, 0xff843C39,
+			0xffDE9ED6, 0xffCE6DBD, 0xffA55194, 0xff7B4173
+		];
+
+		
+		/**
+		 * Generates a categorical color palette
+		 * @param size the number of colors to include
+		 * @param colors an array of category colors to use. If null, a
+		 *  default category color palette will be used.
+		 * @param alpha the alpha value for this palette's colors
+		 * @return the categorical color palette
+		 */
+		public static function category(size:int=20, colors:Array=null,
+										alpha:Number=1.0):ColorPalette
+		{
+			if (colors==null)
+				colors = size<=10 ? CATEGORY_COLORS_10 : CATEGORY_COLORS_20;
+			var a:uint = uint(255 * alpha) % 256;
+			var cm:Array = new Array(size);
+			for (var i:uint=0; i<size; ++i) {
+				cm[i] = Colors.setAlpha(colors[i % colors.length], a);
+			}
+			return new ColorPalette(cm);
+		}
+		
+		/**
+	     * Generates a color palette that uses a "cool", blue-heavy color scheme.
+	     * @param size the size of the color palette
+	     * @return the color palette
+	     */
+	    public static function cool(size:int=DEFAULT_SIZE):ColorPalette
+	    {
+	    	return ramp(0xff00ffff, 0xffff00ff, size);
+	    }
+	
+	    /**
+	     * Generates a color palette that moves from black to red to yellow
+	     * to white.
+	     * @param size the size of the color palette
+	     * @return the color palette
+	     */
+	    public static function hot(size:int=DEFAULT_SIZE):ColorPalette
+	    {
+	        var cm:Array = new Array(size), r:Number, g:Number, b:Number;
+	        var n:int = int(2*size/8);
+	        
+	        for (var i:uint=0; i<size; i++) {
+	            r = i<n ? (i+1)/n : 1;
+	            g = i<n ? 0 : (i<2*n ? (i-n)/n : 1);
+	            b = i<2*n ? 0 : (i-2*n)/(size-2*n);
+	            cm[i] = Colors.rgba(255*r, 255*g, 255*b);
+	        }
+			var f:Number = 1/4;
+	        return new ColorPalette(cm, [0, f, 2*f, 1]);
+	    }
+		
+		/**
+	     * Generates a color palette that "ramps" from one color to another.
+	     * @param min the color corresponding to the minimum scale value
+	     * @param max the color corresponding to the maximum scale value
+	     * @param size the size of the color palette
+	     * @return the color palette
+	     */
+		public static function ramp(min:uint=0xfff1eef6, max:uint=0xff045a8d,
+			size:int=DEFAULT_SIZE):ColorPalette
+		{
+			var cm:Array = new Array(size);
+			for (var i:uint=0; i<size; ++i) {
+				cm[i] = Colors.interpolate(min, max, i/(size-1));
+			}
+			return new ColorPalette(cm, [0,1]);
+		}
+		
+		/**
+	     * Generates a color palette of color ramps diverging from a central
+	     * value.
+	     * @param min the color corresponding to the minimum scale value
+	     * @param mid the color corresponding to the central scale value
+	     * @param max the color corresponding to the maximum scale value
+	     * @param f an interpolation fraction specifying the position of the
+	     *  central value
+	     * @param size the size of the color palette
+	     * @return the color palette
+	     */
+		public static function diverging(min:uint=0xffd73027,
+			mid:uint=0xffffffbf, max:uint=0xff1a9850,
+			f:Number=0.5, size:int=DEFAULT_SIZE):ColorPalette
+		{
+			var cm:Array = new Array(size);
+			var mp:int = int(f*size), i:uint, j:uint;
+			for (i=0; i<mp; ++i) {
+				cm[i] = Colors.interpolate(min, mid, i/mp);
+			}
+			mp = size - mp - 1;
+			for (j=0; i<size; ++i, ++j) {
+				cm[i] = Colors.interpolate(mid, max, j/mp);
+			}
+			return new ColorPalette(cm, [0,f,1]);
+		}
+		
+	} // end of class ColorPalette
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Stats.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Stats.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Stats.as	(revision 15)
@@ -0,0 +1,185 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	import flash.utils.Dictionary;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	
+	/**
+	 * Utility class for computing statistics for a collection of values.
+	 */
+	public class Stats
+	{
+		/** Constant indicating numerical values. */
+		public static const NUMBER:int = 0;
+		/** Constant indicating date/time values. */
+		public static const DATE:int   = 1;
+		/** Constant indicating arbitrary object values. */
+		public static const OBJECT:int = 2;
+		
+		private var _type:int = -1;
+		private var _comp:Function = null;
+		
+		private var _num:Number = 0;
+		private var _distinct:Number = 0;
+		private var _elm:Array = null;
+		
+		private var _minObject:Object = null;
+		private var _maxObject:Object = null;
+		
+		private var _min:Number = Number.MAX_VALUE;
+		private var _max:Number = Number.MIN_VALUE;
+		private var _sum:Number = 0;
+		private var _stdev:Number = 0;
+		
+		/** The data type of the collection, one of NUMBER, DATE, or OBJECT. */
+		public function get dataType():int { return _type; }
+		/** A sorted array of all the values. */
+		public function get values():Array { return _elm; }
+		/** A sorted array of all unique values in the collection. */
+		public function get distinctValues():Array {
+			// get array with only unique items
+			var dists:Array = [];
+			if (_elm==null || _elm.length == 0) return dists;
+			dists.push(_elm[0]);
+			for (var i:int=1, j:int=0; i<_num; ++i) {
+				if (!equal(_elm[i], dists[j])) {
+					dists.push(_elm[i]); ++j;
+				}
+			}
+			return dists;
+		}
+		/** The minimum value (for numerical data). */
+		public function get minimum():Number { return _min; }
+		/** The maximum value (for numerical data). */
+		public function get maximum():Number { return _max; }
+		/** The sum of all the values (for numerical data). */
+		public function get sum():Number { return _sum; }
+		/** The average of all the values (for numerical data). */
+		public function get average():Number { return _sum / _num; }
+		/** The standard deviation of all the values (for numerical data). */
+		public function get stddev():Number { return _stdev; }
+		/** The standard error of all the values (for numerical data). */
+		public function get stderr():Number { return stddev / Math.sqrt(_num); }
+		/** The total number of values. */
+		public function get count():Number { return _num; }
+		/** The total number of distinct values. */
+		public function get distinct():Number { return _distinct; }
+		
+		/** The minimum value (for date/time values). */
+		public function get minDate():Date { return _minObject as Date; }
+		/** The maximum value (for date/time values). */
+		public function get maxDate():Date { return _maxObject as Date; }
+		
+		/** The minimum value (for arbitrary objects). */
+		public function get minObject():Object { return _minObject; }
+		/** The maximum value (for arbitrary objects). */
+		public function get maxObject():Object { return _maxObject; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new Stats instance using the given input data. If the
+		 * field argument is null, it is assumed that the input data array
+		 * directly contains the values to analyze. If the field argument is
+		 * non-null, values will be extracted from the objects in the input
+		 * array using the specified property name.
+		 * @param data an input data array. The data to analyze may be
+		 *  contained directly in the array, or may be properties of the
+		 *  objects contained in the array.
+		 * @param field a property name. This property will be used to extract
+		 *  data values from the objects in the data array. If null, the
+		 *  objects in the data array will be used directly.
+		 * @param comparator the comparator function to use to sort the data.
+		 *  If null, the natural sort order will be used.
+		 * @param copy flag indicating if the input data array should be
+		 *  copied to a new array. This flag only applied when the field
+		 *  argument is null. In false, the input data array will be sorted.
+		 *  If true, the array will be copied before being sorted. The default
+		 *  behavior is to make a copy.
+		 */
+		public function Stats(data:Array, field:String=null,
+							  comparator:Function=null, copy:Boolean=true)
+		{
+			_comp = comparator;
+			init(data, field, copy);
+		}
+		
+		private function init(data:Array, field:String, copy:Boolean):void
+		{
+			// INVARIANT: properties must be set to default values
+			// TODO: how to handle null values?
+						
+			// collect all values into element array
+			_num = data.length; if (_num==0) return;
+			_elm = (field==null ? (copy ? Arrays.copy(data) : data)
+								: new Array(_num));
+			if (field != null) {
+				var p:Property = Property.$(field);
+				for (var i:uint=0; i<_num; ++i) {
+					_elm[i] = p.getValue(data[i]);
+				}
+			}
+			
+			// determine data type
+			for (i=0; i<_num; ++i) {
+				var v:Object = _elm[i], type:int;
+				type = v is Date ? DATE : (v is Number ? NUMBER : OBJECT);
+
+				if (_type == -1) {
+					_type = type; // seed type
+				} else if (type != _type) {
+					_type = OBJECT; // punt if no match
+					break;
+				}
+			}
+			
+			// sort data values
+			var opt:int = (_type==OBJECT ? 0 : Array.NUMERIC);
+			if (_comp==null) _elm.sort(opt); else _elm.sort(_comp, opt);
+			
+			// count unique values
+			_distinct = 1; var j:uint = 0;
+			for (i=1; i<_num; ++i) {
+				if (!equal(_elm[i], _elm[j])) { ++_distinct; j=i;	}
+			}
+			
+			// populate stats
+			var N:int = _num-1;
+			if (_type == NUMBER)
+			{
+				_min = (_minObject = _elm[0]) as Number;
+				_max = (_maxObject = _elm[N]) as Number;
+				
+				var ss:Number = 0, x:Number;
+				for each (x in _elm) {
+					_sum += x;
+					ss += x*x;
+				}
+				_stdev = Math.sqrt(ss/_num - average*average);
+			}
+			else
+			{
+				_minObject = _elm[0];
+				_maxObject = _elm[N];
+			}
+		}
+		
+		/**
+		 * Tests for equality between two values. This method is necessary
+		 * because the <code>==</code> operator checks object equality and
+		 * not value equality for <code>Date</code> instances.
+		 * @param a the first object to compare
+		 * @param b the second object to compare
+		 * @returns true if the object values are equal, false otherwise
+		 */
+		public static function equal(a:*, b:*):Boolean
+		{
+			if (a is Date && b is Date) {
+				return (a as Date).time == (b as Date).time;
+			} else {
+				return a == b;
+			}
+		}
+		
+	} // end of class Stats
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Dates.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Dates.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Dates.as	(revision 15)
@@ -0,0 +1,226 @@
+package gssim.gssimstudio.editor.flare.util
+{	
+	/**
+	 * Utility methods for working with Date instances.
+	 */
+	public class Dates
+	{
+		// enumerated constants
+		/** Constant indicating a time span of one or more years. */
+		public static const YEARS:int        = 0;
+		/** Constant indicating a time span on the order of months. */
+		public static const MONTHS:int       = -1;
+		/** Constant indicating a time span on the order of days. */
+		public static const DAYS:int         = -2;
+		/** Constant indicating a time span on the order of hours. */
+		public static const HOURS:int        = -3;
+		/** Constant indicating a time span on the order of minutes. */
+		public static const MINUTES:int      = -4;
+		/** Constant indicating a time span on the order of seconds. */
+		public static const SECONDS:int      = -5;
+		/** Constant indicating a time span on the order of milliseconds. */
+		public static const MILLISECONDS:int = -6;
+		/** Constant indicating a time span on the order of weeks. */
+		public static const WEEKS:int = -10;
+		
+		/** Number of milliseconds in a minute. */
+		public static const MS_MIN:Number  = 60*1000;
+		/** Number of milliseconds in an hours. */
+		public static const MS_HOUR:Number = 60*60*1000;
+		/** Number of milliseconds in a day. */
+		public static const MS_DAY:Number  = 24*60*60*1000;
+		
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function Dates() {
+			throw new Error("This is an abstract class.");
+		}
+		
+		// -- Conversion ------------------------------------------------------
+		
+		/**
+		 * Given a date, returns a date instance of the same time in Univeral
+		 * Coordinated Time (UTC).
+		 * @param d the date to convert
+		 */
+		public static function toUTC(d:Date) : Date {
+			return new Date(d.fullYearUTC, d.monthUTC, d.dateUTC, d.hoursUTC,
+							d.minutesUTC, d.secondsUTC, d.millisecondsUTC);
+		}
+		
+		// -- Date Arithmetic -------------------------------------------------
+		
+		/**
+		 * Adds years to a date instance.
+		 * @param d the date
+		 * @param x the number of years to add (can be negative to subtract)
+		 * @return a new Date representing the new date and time
+		 */
+		public static function addYears(d:Date, x:int) : Date {
+			return new Date(d.fullYear+x, d.month, d.date, d.hours, d.minutes, d.seconds, d.milliseconds);
+		}
+		
+		/**
+		 * Adds months to a date instance.
+		 * @param d the date
+		 * @param x the number of months to add (can be negative to subtract)
+		 * @return a new Date representing the new date and time
+		 */
+		public static function addMonths(d:Date, x:int) : Date {
+			var y:Number = Math.floor(x / 12); x -= 12*y;
+			var m:Number = d.month + x;
+			if (m > 11) {
+				y += 1;
+				m -= 12;
+			} else if (m < 0) {
+				y -= 1;
+				m += 12;
+			}
+			return new Date(d.fullYear+y, m, d.date, d.hours, d.minutes, d.seconds, d.milliseconds);
+		}
+		
+		/**
+		 * Adds days to a date instance.
+		 * @param d the date
+		 * @param x the number of days to add (can be negative to subtract)
+		 * @return a new Date representing the new date and time
+		 */
+		public static function addDays(d:Date, x:int) : Date {
+			return new Date(d.time + MS_DAY * x);
+		}
+		
+		/**
+		 * Adds hours to a date instance.
+		 * @param d the date
+		 * @param x the number of hours to add (can be negative to subtract)
+		 * @return a new Date representing the new date and time
+		 */
+		public static function addHours(d:Date, x:int) : Date {
+			return new Date(d.time + MS_HOUR * x);
+		}
+		
+		/**
+		 * Adds minutes to a date instance.
+		 * @param d the date
+		 * @param x the number of minutes to add (can be negative to subtract)
+		 * @return a new Date representing the new date and time
+		 */
+		public static function addMinutes(d:Date, x:int) : Date {
+			return new Date(d.time + MS_MIN * x);
+		}
+		
+		/**
+		 * Adds seconds to a date instance.
+		 * @param d the date
+		 * @param x the number of seconds to add (can be negative to subtract)
+		 * @return a new Date representing the new date and time
+		 */
+		public static function addSeconds(d:Date, x:int) : Date {
+			return new Date(d.time + 1000 * x);
+		}
+		
+		// -- Time Spans ------------------------------------------------------
+				
+		/**
+		 * Rounds a date according to a particular time span. Date values are
+		 * rounded to the minimum date/time value of the time span (the first
+		 * day in a year, month, or week, or the beginning of a day, hours,
+		 * minute, second, etc).
+		 * @param t the date to round
+		 * @param span the time span to which the date should be rounded, legal
+		 *  values are YEARS, MONTHS, WEEKS, DAYS, HOURS, MINUTES, SECONDS, or
+		 *  MILLISECONDS
+		 * @param roundUp if true, the date will be rounded up to nearest value,
+		 * otherwise it will be rounded down (the default)
+		 * @return a new Date representing the rounded date and time.
+		 */
+		public static function roundTime(t:Date, span:int, roundUp:Boolean=false) : Date
+		{
+			var d:Date = t;
+			if (span > YEARS) {
+				d = new Date(t.fullYear, 0);
+				if (roundUp) d = addYears(d, 1);
+			} else if (span == MONTHS) {
+				d = new Date(t.fullYear, t.month);
+				if (roundUp) d = addMonths(d, 1);				
+			} else if (span == DAYS) {
+				d = new Date(t.fullYear, t.month, t.date);
+				if (roundUp) d = addDays(d, 1);
+			} else if (span == HOURS) {
+				d = new Date(t.fullYear, t.month, t.date, t.hours);
+				if (roundUp) d = addHours(d, 1);
+			} else if (span == MINUTES) {
+				d = new Date(t.fullYear, t.month, t.date, t.hours, t.minutes);
+				if (roundUp) d = addMinutes(d, 1);
+			} else if (span == SECONDS) {
+				d = new Date(t.fullYear, t.month, t.date, t.hours, t.minutes, t.seconds);
+				if (roundUp) d = addSeconds(d, 1);
+			} else if (span == MILLISECONDS) {
+				d = new Date(d.time + (roundUp ? 1 : -1));
+			} else if (span == WEEKS) {
+				d = new Date(t.fullYear, t.month, t.date);
+				if (roundUp) {
+					d = addDays(d, 7 - d.day);
+				} else {
+					d = addDays(d, -d.day);
+				}
+			}
+			return d;
+		}
+		
+		/**
+		 * Given two dates, returns a measure of the time span between them.
+		 * @param t the first date to compare
+		 * @param s the second date to compare
+		 * @return an integer value indicating the time span between dates. If
+		 * the return value is positive, it represents the number of years
+		 * between dates. Otherwise, the return value is one of MONTHS, DAYS,
+		 * HOURS, MINUTES, SECONDS, or MILLISECONDS.
+		 */
+		public static function timeSpan(t:Date, s:Date) : int
+		{
+			var span:Number = s.time - t.time;
+			var days:Number = span / MS_DAY;
+
+            if (days >= 365*2) 			return (1 + s.fullYear-t.fullYear);
+            else if (days >= 60)   		return MONTHS;
+            else if (span/MS_DAY > 1)	return DAYS;
+            else if (span/MS_HOUR > 1)	return HOURS;
+            else if (span/MS_MIN > 1)	return MINUTES;
+            else if (span/1000.0 > 1)	return SECONDS;
+            else						return MILLISECONDS;
+		}
+		
+		/**
+		 * Returns the number of milliseconds needed to step one time step
+		 * forward according to the given time span measure.
+		 * @param span the time span for which to return a time step value.
+		 *  Legal values are any positive numbers (representing years) or DAYS,
+		 *  HOURS, MINUTES, SECONDS, and MILLISECONDS. Note that the MONTHS
+		 *  time span is not supported and will result in a zero return value.
+		 * @return the number of milliseconds needed to more one time step
+		 *  ahead according to the input time span. For years (positive
+		 *  integer input), this step is the nearest power of ten less than the
+		 *  input value.
+		 */
+		public static function timeStep(span:int):Number {
+			if (span > YEARS) {
+				return Math.pow(10, Math.floor(Maths.log(Math.max(1,span-1),10)));
+			} else if (span == MONTHS) {
+				return 0;
+			} else if (span == DAYS) {
+				return MS_DAY;
+			} else if (span == HOURS) {
+				return MS_HOUR;
+			} else if (span == MINUTES) {
+				return MS_MIN;
+			} else if (span == SECONDS) {
+				return 1000;
+			} else {
+				return 1;
+			}
+		}
+		
+	} // end of class DateUtil
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Arrays.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Arrays.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Arrays.as	(revision 15)
@@ -0,0 +1,267 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	/**
+	 * Utility methods for working with arrays.
+	 */
+	public class Arrays
+	{
+		public static const EMPTY:Array = new Array(0);
+		
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function Arrays() {
+			throw new ArgumentError("This is an abstract class.");
+		}
+		
+		/**
+		 * Returns the maximum value in an array. Comparison is determined
+		 * using the greater-than operator against arbitrary types.
+		 * @param a the array
+		 * @param p an optional property from which to extract the value.
+		 *  If this is null, the immediate contents of the array are compared.
+		 * @return the maximum value
+		 */
+		public static function max(a:Array, p:Property=null):Number
+		{
+			var x:Number = Number.MIN_VALUE;
+			if (p) {
+				var v:Number;
+				for (var i:uint=0; i<a.length; ++i) {
+					v = p.getValue(a[i]);
+					if (v > x) x = v;
+				}
+			} else {
+				for (i=0; i<a.length; ++i) {
+					if (a[i] > x) x = a[i];
+				}
+			}
+			return x;
+		}
+		
+		/**
+		 * Returns the index of a maximum value in an array. Comparison is
+		 * determined using the greater-than operator against arbitrary types.
+		 * @param a the array
+		 * @param p an optional property from which to extract the value.
+		 *  If this is null, the immediate contents of the array are compared.
+		 * @return the index of a maximum value
+		 */
+		public static function maxIndex(a:Array, p:Property=null):Number
+		{
+			var x:Number = Number.MIN_VALUE;
+			var idx:int = -1;
+			
+			if (p) {
+				var v:Number;
+				for (var i:uint=0; i<a.length; ++i) {
+					v = p.getValue(a[i]);
+					if (v > x) { x = v; idx = i; }
+				}
+			} else {
+				for (i=0; i<a.length; ++i) {
+					if (a[i] > x) { x = a[i]; idx = i; }
+				}
+			}
+			return idx;
+		}
+		
+		/**
+		 * Returns the minimum value in an array. Comparison is determined
+		 * using the less-than operator against arbitrary types.
+		 * @param a the array
+		 * @param p an optional property from which to extract the value.
+		 *  If this is null, the immediate contents of the array are compared.
+		 * @return the minimum value
+		 */
+		public static function min(a:Array, p:Property=null):Number
+		{
+			var x:Number = Number.MAX_VALUE;
+			if (p) {
+				var v:Number;
+				for (var i:uint=0; i<a.length; ++i) {
+					v = p.getValue(a[i]);
+					if (v < x) x = v;
+				}
+			} else {
+				for (i=0; i<a.length; ++i) {
+					if (a[i] < x) x = a[i];
+				}
+			}
+			return x;
+		}
+		
+		/**
+		 * Returns the index of a minimum value in an array. Comparison is
+		 * determined using the less-than operator against arbitrary types.
+		 * @param a the array
+		 * @param p an optional property from which to extract the value.
+		 *  If this is null, the immediate contents of the array are compared.
+		 * @return the index of a minimum value
+		 */
+		public static function minIndex(a:Array, p:Property=null):Number
+		{
+			var x:Number = Number.MAX_VALUE, idx:int = -1;
+			if (p) {
+				var v:Number;
+				for (var i:uint=0; i<a.length; ++i) {
+					v = p.getValue(a[i]);
+					if (v < x) { x = v; idx = i; }
+				}
+			} else {
+				for (i=0; i<a.length; ++i) {
+					if (a[i] < x) { x = a[i]; idx = i; }
+				}
+			}
+			return idx;
+		}
+		
+		/**
+		 * Fills an array with a given value.
+		 * @param a the array
+		 * @param o the value with which to fill the array
+		 */
+		public static function fill(a:Array, o:*) : void
+		{
+			for (var i:uint = 0; i<a.length; ++i) {
+				a[i] = o;
+			}
+		}
+		
+		/**
+		 * Makes a copy of an array or copies the contents of one array to
+		 * another.
+		 * @param a the array to copy
+		 * @param b the array to copy values to. If null, a new array is
+		 *  created.
+		 * @param a0 the starting index from which to copy values
+		 *  of the input array
+		 * @param b0 the starting index at which to write value into the
+		 *  output array
+		 * @param len the number of values to copy
+		 * @return the target array containing the copied values
+		 */
+		public static function copy(a:Array, b:Array=null, a0:int=0, b0:int=0, len:int=-1) : Array {
+			len = (len < 0 ? a.length : len);
+			if (b==null) {
+				b = new Array(b0+len);
+			} else {
+				while (b.length < b0+len) b.push(null);
+			}
+
+			for (var i:uint = 0; i<len; ++i) {
+				b[b0+i] = a[a0+i];
+			}
+			return b;
+		}
+		
+		/**
+		 * Clears an array instance, removing all values.
+		 * @param a the array to clear
+		 */
+		public static function clear(a:Array):void
+		{
+			while (a.length > 0) a.pop();
+		}
+				
+		/**
+		 * Removes an element from an array. Only the first instance of the
+		 * value is removed.
+		 * @param a the array
+		 * @param o the value to remove
+		 * @return the index location at which the removed element was found,
+		 * negative if the value was not found.
+		 */
+		public static function remove(a:Array, o:Object) : int {
+			var idx:int = a.indexOf(o);
+			if (idx == a.length-1) {
+				a.pop();
+			} else if (idx >= 0) {
+				a.splice(idx, 1);
+			}
+			return idx;
+		}
+		
+		/**
+		 * Removes the array element at the given index.
+		 * @param a the array
+		 * @param idx the index at which to remove an element
+		 * @return the removed element
+		 */
+		public static function removeAt(a:Array, idx:uint) : Object {
+			if (idx == a.length-1) {
+				return a.pop();
+			} else {
+				var x:Object = a[idx];
+				a.splice(idx,1);
+				return x;
+			}
+		}
+		
+		/**
+		 * Performs a binary search over the input array for the given key
+		 * value, optionally using a provided property to extract from array
+		 * items and a custom comparison function.
+		 * @param a the array to search over
+		 * @param key the key value to search for
+		 * @param prop the property to retrieve from objecs in the array. If null
+		 *  (the default) the array values will be used directly.
+		 * @param cmp an optional comparison function
+		 * @return the index of the given key if it exists in the array,
+         *  otherwise -1 times the index value at the insertion point that
+         *  would be used if the key were added to the array.
+         */
+		public static function binarySearch(a:Array, key:Object,
+			prop:String=null, cmp:Function=null) : int
+		{
+			var p:Property = prop ? Property.$(prop) : null;
+			if (cmp == null)
+				cmp = function(a:*,b:*):int {return a>b ? 1 : a<b ? -1 : 0;}
+			
+			var x1:int = 0, x2:int = a.length, i:int = (x2>>1);
+        	while (x1 < x2) {
+        		var c:int = cmp(p ? p.getValue(a[i]) : a[i], key);
+        		if (c == 0) {
+                	return i;
+            	} else if (c < 0) {
+                	x1 = i + 1;
+            	} else {
+                	x2 = i;
+            	}
+            	i = x1 + ((x2 - x1)>>1);
+        	}
+        	return -1*(i+1);
+		}
+		
+		/**
+		 * Sets a named property value for items stored in an array.
+		 * The value can take a number of forms:
+		 * <ul>
+		 *  <li>If the value is a <code>Function</code>, it will be evaluated
+		 *      for each element and the result will be used as the property
+		 *      value for that element.</li>
+		 *  <li>If the value is an <code>IEvaluable</code> instance, it will be
+		 *      evaluated for each element and the result will be used as the
+		 *      property value for that element.</li>
+		 *  <li>In all other cases, the property value will be treated as a
+		 *      literal and assigned for all elements.</li>
+		 * </ul>
+		 * @param list the array to set property values for
+		 * @param name the name of the property to set
+		 * @param value the value of the property to set
+		 * @param filter a filter function determining which items
+		 *  in the array should be processed
+		 * @param p an optional <code>IValueProxy</code> for setting the values
+		 */
+		public static function setProperty(a:Array,
+			name:String, value:*, filter:Function, p:IValueProxy=null):void
+		{
+			if (p == null) p = Property.proxy;
+			var v:Function = value is Function ? value as Function :
+				value is IEvaluable ? IEvaluable(value).eval : null;
+			for each (var o:Object in a) if (filter==null || filter(o))
+				p.setValue(o, name, v!=null ? v(p.$(o)) : value);
+		}
+
+	} // end of class Arrays
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Colors.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Colors.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Colors.as	(revision 15)
@@ -0,0 +1,317 @@
+package gssim.gssimstudio.editor.flare.util
+{	
+	/**
+	 * Utility methods for working with colors.
+	 */
+	public class Colors
+	{
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function Colors() {
+			throw new Error("This is an abstract class.");
+		}
+				
+		/**
+		 * Returns the alpha component of a color value
+		 * @param c the color value
+		 * @return the alpha component
+		 */
+		public static function a(c:uint):uint
+		{
+			return (c >> 24) & 0xFF;
+		}
+		
+		/**
+		 * Returns the red component of a color value
+		 * @param c the color value
+		 * @return the red component
+		 */
+		public static function r(c:uint):uint
+		{
+			return (c >> 16) & 0xFF;
+		}
+		
+		/**
+		 * Returns the green component of a color value
+		 * @param c the color value
+		 * @return the green component
+		 */
+		public static function g(c:uint):uint
+		{
+			return (c >> 8) & 0xFF;
+		}
+		
+		/**
+		 * Returns the blue component of a color value
+		 * @param c the color value
+		 * @return the blue component
+		 */
+		public static function b(c:uint):uint
+		{
+			return (c & 0xFF);
+		}
+		
+		/**
+		 * Returns a grayscale color value with the given brightness
+		 * @param v the brightness component (0-255)
+		 * @param a the alpha component (0-255, 255 by default)
+		 * @return the color value
+		 */
+		public static function gray(v:uint, a:uint=255):uint
+		{
+			return ((a & 0xFF) << 24) | ((v & 0xFF) << 16) |
+				   ((v & 0xFF) <<  8) |  (v & 0xFF);
+		}
+		
+		/**
+		 * Returns a color value with the given red, green, blue, and alpha
+		 * components
+		 * @param r the red component (0-255)
+		 * @param g the green component (0-255)
+		 * @param b the blue component (0-255)
+		 * @param a the alpha component (0-255, 255 by default)
+		 * @return the color value
+		 * 
+		 */
+		public static function rgba(r:uint, g:uint, b:uint, a:uint=255):uint
+		{
+			return ((a & 0xFF) << 24) | ((r & 0xFF) << 16) |
+				   ((g & 0xFF) <<  8) |  (b & 0xFF);
+		}
+		
+		/**
+		 * Returns a color value by updating the alpha component of another
+		 * color value.
+		 * @param c a color value
+		 * @param a the desired alpha component (0-255)
+		 * @return a color value with adjusted alpha component
+		 */
+		public static function setAlpha(c:uint, a:uint):uint
+		{
+			return ((a & 0xFF) << 24) | (c & 0x00FFFFFF);
+		}
+		
+		/**
+		 * Returns the RGB color value for a color specified in HSV (hue,
+		 * saturation, value) color space.
+		 * @param h the hue, a value between 0 and 1
+		 * @param s the saturation, a value between 0 and 1
+		 * @param v the value (brighntess), a value between 0 and 1
+		 * @param a the (optional) alpha value, an integer between 0 and 255
+		 *  (255 is the default)
+		 * @return the corresponding RGB color value
+		 */
+		public static function hsv(h:Number, s:Number, v:Number, a:uint=255):uint
+		{
+			var r:uint=0, g:uint=0, b:uint=0;
+            if (s == 0) {
+                r = g = b = uint(v * 255 + .5);
+            } else {
+            	var i:Number = (h - Math.floor(h)) * 6.0;
+                var f:Number = i - Math.floor(i);
+                var p:Number = v * (1 - s);
+                var q:Number = v * (1 - s * f);
+                var t:Number = v * (1 - (s * (1 - f)));
+                switch (int(i))
+                {
+                    case 0:
+                        r = uint(v * 255 + .5);
+                        g = uint(t * 255 + .5);
+                        b = uint(p * 255 + .5);
+                        break;
+                    case 1:
+                        r = uint(q * 255 + .5);
+                        g = uint(v * 255 + .5);
+                        b = uint(p * 255 + .5);
+                        break;
+                    case 2:
+                        r = uint(p * 255 + .5);
+                        g = uint(v * 255 + .5);
+                        b = uint(t * 255 + .5);
+                        break;
+                    case 3:
+                        r = uint(p * 255 + .5);
+                        g = uint(q * 255 + .5);
+                        b = uint(v * 255 + .5);
+                        break;
+                    case 4:
+                        r = uint(t * 255 + .5);
+                        g = uint(p * 255 + .5);
+                        b = uint(v * 255 + .5);
+                        break;
+                    case 5:
+                        r = uint(v * 255 + .5);
+                        g = uint(p * 255 + .5);
+                        b = uint(q * 255 + .5);
+                        break;
+                }
+            }
+            return rgba(r, g, b, a);
+		}
+		
+		/**
+		 * Returns the hue component of an ARGB color. 
+		 * @param c the input color
+		 * @return the hue component of the color is HSV color space as a
+		 *  number between 0 and 1
+		 */
+		public static function hue(c:uint):Number
+        {
+			var r:uint, g:uint, b:uint, cmax:uint, cmin:uint;
+			var h:Number, range:Number;
+			
+			r = (c >> 16) & 0xFF;
+			g = (c >> 8) & 0xFF;
+			b = (c & 0xFF);
+			cmax = (r > g) ? r : g; if (b > cmax) cmax = b;
+            cmin = (r < g) ? r : g; if (b < cmin) cmin = b;
+            range = Number(cmax - cmin);
+
+            if (range == 0) {
+                h = 0;
+            } else {
+            	var rc:Number = Number(cmax - r) / range;
+                var gc:Number = Number(cmax - g) / range;
+                var bc:Number = Number(cmax - b) / range;
+                if (r == cmax)
+                    h = bc - gc;
+                else if (g == cmax)
+                    h = 2.0 + rc - bc;
+                else
+                    h = 4.0 + gc - rc;
+                	h = h / 6.0;
+                if (h < 0)
+                    h = h + 1.0;
+            }
+            return h;
+        }
+        
+        /**
+		 * Returns the saturation component of an ARGB color. 
+		 * @param c the input color
+		 * @return the saturation of the color is HSV color space as a
+		 *  number between 0 and 1
+		 */
+        public static function saturation(c:uint):Number
+        {
+        	var r:uint, g:uint, b:uint, cmax:uint, cmin:uint;
+			r = (c >> 16) & 0xFF;
+			g = (c >> 8) & 0xFF;
+			b = (c & 0xFF);
+			cmax = (r > g) ? r : g; if (b > cmax) cmax = b;
+			if (cmax==0) return 0;
+            cmin = (r < g) ? r : g; if (b < cmin) cmin = b;
+            return Number(cmax-cmin) / cmax;
+        }
+        
+        /**
+		 * Returns the value (brightness) component of an ARGB color. 
+		 * @param c the input color
+		 * @return the value component of the color is HSV color space as a
+		 *  number between 0 and 1
+		 */
+        public static function value(c:uint):Number
+        {
+        	var r:uint, g:uint, b:uint, cmax:uint;
+			r = (c >> 16) & 0xFF;
+			g = (c >> 8) & 0xFF;
+			b = (c & 0xFF);
+			cmax = (r > g) ? r : g; if (b > cmax) cmax = b;
+            return cmax / 255.0;
+        }
+		
+		/**
+	     * Interpolate between two color values by the given mixing proportion.
+	     * A mixing fraction of 0 will result in c1, a value of 1.0 will result
+	     * in c2, and value of 0.5 will result in the color mid-way between the
+	     * two in RGB color space.
+	     * @param c1 the starting color
+	     * @param c2 the target color
+	     * @param f a fraction between 0 and 1 controlling the interpolation
+	     * @return the interpolated color
+	     */
+		public static function interpolate(c1:uint, c2:uint, f:Number):uint
+		{
+			var t:uint;
+			return rgba(
+				(t=r(c1)) + f*(r(c2)-t),
+				(t=g(c1)) + f*(g(c2)-t),
+				(t=b(c1)) + f*(b(c2)-t),
+				(t=a(c1)) + f*(a(c2)-t)
+			);
+		}
+    
+	    /**
+	     * Get a darker shade of an input color.
+	     * @param c a color value
+	     * @return a darkened color value
+	     */
+	    public static function darker(c:uint, s:Number=1):uint
+	    {
+	    	s = Math.pow(0.7, s);
+	        return rgba(Math.max(0, int(s*r(c))),
+	                    Math.max(0, int(s*g(c))),
+	                    Math.max(0, int(s*b(c))),
+	                    a(c));
+	    }
+	
+	    /**
+	     * Get a brighter shade of an input color.
+	     * @param c a color value
+	     * @return a brighter color value
+	     */
+	    public static function brighter(c:uint, s:Number=1):uint
+	    {
+	    	var cr:uint, cg:uint, cb:uint, i:uint;
+	    	s = Math.pow(0.7, s);
+	    	
+	        cr = r(c), cg = g(c), cb = b(c);
+	        i = 30;
+	        if (cr == 0 && cg == 0 && cb == 0) {
+	           return rgba(i, i, i, a(c));
+	        }
+	        if ( cr > 0 && cr < i ) cr = i;
+	        if ( cg > 0 && cg < i ) cg = i;
+	        if ( cb > 0 && cb < i ) cb = i;
+	
+	        return rgba(Math.min(255, (int)(cr/s)),
+	                    Math.min(255, (int)(cg/s)),
+	                    Math.min(255, (int)(cb/s)),
+	                    a(c));
+	    }
+	    
+	    /**
+	     * Get a desaturated shade of an input color.
+	     * @param c a color value
+	     * @return a desaturated color value
+	     */
+	    public static function desaturate(c:uint):uint
+	    {
+	        var a:uint = c & 0xff000000;
+	        var cr:Number = Number(r(c));
+	        var cg:Number = Number(g(c));
+	        var cb:Number = Number(b(c));
+	
+	        cr *= 0.2125; // red band weight
+	        cg *= 0.7154; // green band weight
+	        cb *= 0.0721; // blue band weight
+	
+	        var gray:uint = uint(Math.min(int(cr+cg+cb),0xff)) & 0xff;
+	        return a | (gray << 16) | (gray << 8) | gray;
+	    }
+	    
+	    /**
+	     * A color transform matrix that desaturates colors to corresponding
+	     * grayscale values. Can be used with the
+	     * <code>flash.filters.ColorMatrixFilter</code> class.
+	     */
+	    public static function get desaturationMatrix():Array {
+	    	return [0.2125, 0.7154, 0.0721, 0, 0,
+	    			0.2125, 0.7154, 0.0721, 0, 0,
+	    			0.2125, 0.7154, 0.0721, 0, 0,
+	    			     0,      0,      0, 1, 0];
+	    }
+	    
+	} // end of class Colors
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IEvaluable.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IEvaluable.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IEvaluable.as	(revision 15)
@@ -0,0 +1,16 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	/**
+	 * Interface for methods that evaluate an object and return a result.
+	 */
+	public interface IEvaluable
+	{
+		/**
+		 * Evaluates the input object
+		 * @o the object to evaluate
+		 * @return the computed result value
+		 */
+		function eval(o:Object=null):*;
+		
+	} // end of interface IEvaluable
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IPredicate.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IPredicate.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IPredicate.as	(revision 15)
@@ -0,0 +1,17 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	/**
+	 * Interface for methods that evaluate an object and return true or false.
+	 */
+	public interface IPredicate
+	{
+		/**
+		 * Boolean test function that returns true or false for an
+		 * input object.
+		 * @param o the input object
+		 * @return true or false
+		 */
+		function predicate(o:Object):Boolean;
+		
+	} // end of interface IPredicate
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/heap/FibonacciHeap.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/heap/FibonacciHeap.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/heap/FibonacciHeap.as	(revision 15)
@@ -0,0 +1,347 @@
+package gssim.gssimstudio.editor.flare.util.heap
+{
+	/**
+	 * A Fibonacci heap data structure for maintaining a sorted priority queue.
+	 * For more about this particular implementation see
+	 * <a target="_top" href="http://en.wikipedia.org/wiki/Fibonacci_heap">
+	 * Wikipedia's Fibonacci Heap article</a>.
+	 */
+	public class FibonacciHeap
+	{
+		private var _min:HeapNode;
+		private var _size:int;
+
+		/** True if the heap is empty, false otherwise. */
+		public function get empty():Boolean
+		{
+			return _min == null;
+		}
+		
+		/** The number of nodes contained in this heap. */
+		public function get size():int
+		{
+			return _size;
+		}
+		
+		/**
+		 * Clears the heap, removing all nodes.
+		 */
+		public function clear():void
+		{
+			_min = null;
+			_size = 0;
+		}
+
+		/**
+		 * Decrease the key value for a heap node, changing its key and
+		 * potentially re-configuring the heap structure
+		 * @param x the heap node
+		 * @param k the new key value for the node. If this value is greater
+		 *  than the node's current key value an error will be thrown.
+		 */		
+		public function decreaseKey(x:HeapNode, k:Number):void
+		{
+			if (k > x.key)
+            	throw new Error("Only lower key values allowed");
+
+        	x.key = k;
+        	var y:HeapNode = x.parent;
+
+	        if ((y != null) && (x.key < y.key)) {
+    	        cut(x, y);
+        	    cascadingCut(y);
+        	}
+
+        	if (x.key < _min.key) {
+            	_min = x;
+        	}
+		}
+
+		/**
+		 * Removes a node from the heap.
+		 * @param x the heap node to remove
+		 */
+		public function remove(x:HeapNode):void
+    	{
+        	decreaseKey(x, Number.NEGATIVE_INFINITY);
+        	removeMin();
+    	}
+
+		/**
+		 * Inserts a new node into the heap.
+		 * @param data the data to associate with the heap node
+		 * @param key the key value used to sort the heap node
+		 * @return the newly added heap node
+		 */		
+		public function insert(data:Object,
+			key:Number=Number.POSITIVE_INFINITY):HeapNode
+		{
+			var n:HeapNode = new HeapNode(data, key);
+			n.inHeap = true;
+
+        	if (_min != null) {
+            	n.left = _min;
+            	n.right = _min.right;
+            	_min.right = n;
+            	n.right.left = n;
+
+            	if (key < _min.key)
+                	_min = n;
+        	} else {
+            	_min = n;
+        	}
+	        _size++;
+	        return n;
+		}
+
+		/**
+		 * Returns the heap node with the minimum key value.
+		 * @return the heap node with the minimum key value
+		 */
+		public function min():HeapNode
+		{
+			return _min;
+		}
+
+		/**
+		 * Removes and returns the heap node with the minimum key value.
+		 * @return the heap node with the minimum key value
+		 */
+		public function removeMin():HeapNode
+		{
+			var z:HeapNode = _min;
+			if (z == null) return z;
+			
+			var kids:int = z.degree;
+			var x:HeapNode = z.child;
+			var r:HeapNode;
+
+            // for each child of z do...
+            while (kids > 0) {
+                r = x.right;
+
+                // remove x from child list
+                x.left.right = x.right;
+                x.right.left = x.left;
+
+                // add x to root list of heap
+                x.left = _min;
+                x.right = _min.right;
+                _min.right = x;
+                x.right.left = x;
+
+                // set parent[x] to null
+                x.parent = null;
+                x = r;
+                kids--;
+            }
+
+            // remove z from root list of heap
+            z.left.right = z.right;
+            z.right.left = z.left;
+
+            if (z == z.right) {
+                _min = null;
+            } else {
+                _min = z.right;
+                consolidate();
+            }
+
+	        // decrement size of heap and return
+	        _size--;
+	  		z.inHeap = false;
+	        return z;
+		}
+
+		/**
+		 * Constructs the union of two fibonacci heaps.
+		 * @param h1 the first heap
+		 * @param h2 the second heap
+		 * @return the union of the two heaps
+		 */
+		public static function union(h1:FibonacciHeap, h2:FibonacciHeap):FibonacciHeap
+		{
+			var h:FibonacciHeap = new FibonacciHeap();
+					
+	        if (h1 != null && h2 != null) {
+	            h._min = h1._min;
+	
+	            if (h._min != null) {
+	                if (h2._min != null) {
+	                    h._min.right.left = h2._min.left;
+	                    h2._min.left.right = h._min.right;
+	                    h._min.right = h2._min;
+	                    h2._min.left = h._min;
+	                    if (h2._min.key < h1._min.key)
+	                        h._min = h2._min;
+	                }
+	            } else {
+	                h._min = h2._min;
+	            }
+	
+	            h._size = h1._size + h2._size;
+	        }
+	
+	        return h;
+		}
+
+	    private function cascadingCut(y:HeapNode):void
+	    {
+	        var z:HeapNode = y.parent;
+	        if (z != null) {
+	            if (!y.mark) {
+	                y.mark = true;
+	            } else {
+	                cut(y, z);
+	                cascadingCut(z);
+	            }
+	        }
+	    }
+
+	    private function consolidate():void
+	    {
+	    	var arraySize:int = _size + 1;
+	    	var array:Array = new Array(arraySize);
+	    	var i:uint;
+	
+	        // Initialize degree array
+	        for (i=0; i<arraySize; i++)
+	            array[i] = null;
+	
+	        // Find the number of root nodes.
+	        var numRoots:int = 0, d:int;
+	        var x:HeapNode = _min, y:HeapNode;
+	        var next:HeapNode, temp:HeapNode;
+	
+	        if (x != null) {
+	            numRoots++;
+	            x = x.right;
+	
+	            while (x != _min) {
+	                numRoots++;
+	                x = x.right;
+	            }
+	        }
+	
+	        // For each node in root list do...
+	        while (numRoots > 0) {
+	            // Access this node's degree..
+	            d = x.degree;
+	            next = x.right;
+	
+	            // ..and see if there's another of the same degree.
+	            while (array[d] != null) {
+	                // There is, make one of the nodes a child of the other.
+	                y = array[d];
+	
+	                // Do this based on the key value.
+	                if (x.key > y.key) {
+	                    temp = y;
+	                    y = x;
+	                    x = temp;
+	                }
+	
+	                // FiboHeapNode y disappears from root list.
+	                link(y, x);
+	
+	                // We've handled this degree, go to next one.
+	                array[d] = null;
+	                d++;
+	            }
+	
+	            // Save this node for later when we might encounter another
+	            // of the same degree.
+	            array[d] = x;
+	
+	            // Move forward through list.
+	            x = next;
+	            numRoots--;
+	        }
+	
+	        // Set min to null (effectively losing the root list) and
+	        // reconstruct the root list from the array entries in array[].
+	        _min = null;
+	
+	        for (i=0; i<arraySize; i++) {
+	            if (array[i] != null) {
+	                // We've got a live one, add it to root list.
+	                if (_min != null) {
+	                    // First remove node from root list.
+	                    array[i].left.right = array[i].right;
+	                    array[i].right.left = array[i].left;
+	
+	                    // Now add to root list, again.
+	                    array[i].left = _min;
+	                    array[i].right = _min.right;
+	                    _min.right = array[i];
+	                    array[i].right.left = array[i];
+	
+	                    // Check if this is a new min.
+	                    if (array[i].key < _min.key) {
+	                        _min = array[i];
+	                    }
+	                } else {
+	                    _min = array[i];
+	                }
+	            }
+	        }
+	    }
+
+	    private function cut(x:HeapNode, y:HeapNode):void
+	    {
+	        // remove x from childlist of y and decrement degree[y]
+	        x.left.right = x.right;
+	        x.right.left = x.left;
+	        y.degree--;
+	
+	        // reset y.child if necessary
+	        if (y.child == x) {
+	            y.child = x.right;
+	        }
+	
+	        if (y.degree == 0) {
+	            y.child = null;
+	        }
+	
+	        // add x to root list of heap
+	        x.left = _min;
+	        x.right = _min.right;
+	        _min.right = x;
+	        x.right.left = x;
+	
+	        // set parent[x] to nil
+	        x.parent = null;
+	
+	        // set mark[x] to false
+	        x.mark = false;
+	    }
+
+	    private function link(y:HeapNode, x:HeapNode):void
+	    {
+	        // remove y from root list of heap
+	        y.left.right = y.right;
+	        y.right.left = y.left;
+	
+	        // make y a child of x
+	        y.parent = x;
+	
+	        if (x.child == null) {
+	            x.child = y;
+	            y.right = y;
+	            y.left = y;
+	        } else {
+	            y.left = x.child;
+	            y.right = x.child.right;
+	            x.child.right = y;
+	            y.right.left = y;
+	        }
+	
+	        // increase degree[x]
+	        x.degree++;
+	
+	        // set mark[y] false
+	        y.mark = false;
+	    }
+		
+	} // end of class FibonacciHeap
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/heap/HeapNode.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/heap/HeapNode.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/heap/HeapNode.as	(revision 15)
@@ -0,0 +1,42 @@
+package gssim.gssimstudio.editor.flare.util.heap
+{
+	/**
+	 * A node in a heap data structure.
+	 * For use with the <code>FibonacciHeap</code> class.
+	 * @see flare.analytics.util.FibonacciHeap
+	 */
+	public class HeapNode
+	{
+		/** Arbitrary client data property to store with the node. */
+		public var data:*;
+		/** The parent node of this node. */
+		public var parent:HeapNode;
+		/** A child node of this node. */
+		public var child:HeapNode;
+		/** The right child node of this node. */
+		public var right:HeapNode;
+		/** The left child node of this node. */
+		public var left:HeapNode;
+		/** Boolean flag useful for marking this node. */
+		public var mark:Boolean;
+		/** Flag indicating if this node is currently in a heap. */
+		public var inHeap:Boolean = true;
+		/** Key value used for sorting the heap nodes. */
+		public var key:Number;
+		/** The degree of this heap node (number of child nodes). */
+		public var degree:int;
+	
+		/**
+		 * Creates a new HeapNode
+		 * @param data arbitrary data to store with this node
+		 * @param key the key value to sort on
+		 */
+		function HeapNode(data:*, key:Number)
+		{
+			this.data = data;
+			this.key = key;
+			right = this;
+			left = this;
+		}
+	} // end of class HeapNode
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Maths.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Maths.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Maths.as	(revision 15)
@@ -0,0 +1,440 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	/**
+	 * Utility methods for mathematics not found in the <code>Math</code> class.
+	 */
+	public class Maths
+	{
+		private static var EPSILON:Number = 1e-30;
+		
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function Maths() {
+			throw new ArgumentError("This is an abstract class");
+		}
+		
+		// -- Operators -------------------------------------------------------
+		
+		/**
+		 * Returns the logarithm with a given base value.
+		 * @param x the number for which to compute the logarithm
+		 * @param base the base of the logarithm
+		 * @return the logarithm value
+		 */
+		public static function log(x:Number, base:Number):Number
+		{
+			return Math.log(x) / Math.log(base);
+		}
+		
+		/**
+		 * Rounds an input value down according to its logarithm. The method
+		 *  takes the floor of the logarithm of the value and then uses the
+		 *  resulting value as an exponent for the base value. For example:
+		 * <code>
+		 * trace(Maths.logFloor(13,10)); // prints "10"
+		 * trace(Maths.logFloor(113,10)); // prints "100"
+		 * </code>
+		 * @param x the number for which to compute the logarithm floor
+		 * @param base the base of the logarithm
+		 * @return the rounded-by-logarithm value
+		 */
+		public static function logFloor(x:Number, base:Number):Number {
+			if (x > 0) {
+				return Math.pow(base, Math.floor(Maths.log(x, base)));
+			} else {
+				return -Math.pow(base, -Math.floor(-Maths.log(-x, base)));
+			}
+		}
+		
+		/**
+		 * Rounds an input value up according to its logarithm. The method
+		 *  takes the ceiling of the logarithm of the value and then uses the
+		 *  resulting value as an exponent for the base value. For example:
+		 * <code>
+		 * trace(Maths.logCeil(13,10)); // prints "100"
+		 * trace(Maths.logCeil(113,10)); // prints "1000"
+		 * </code>
+		 * @param x the number for which to compute the logarithm ceiling
+		 * @param base the base of the logarithm
+		 * @return the rounded-by-logarithm value
+		 */
+		public static function logCeil(x:Number, base:Number):Number {
+			if (x > 0) {
+				return Math.pow(base, Math.ceil(Maths.log(x, base)));
+			} else {
+				return -Math.pow(base, -Math.ceil(-Maths.log(-x, base)));
+			}
+		}
+		
+		/**
+		 * Computes a zero-symmetric logarithm. Computes the logarithm of the
+		 * absolute value of the input, and determines the sign of the output
+		 * according to the sign of the input value.
+		 * @param x the number for which to compute the logarithm
+		 * @param b the base of the logarithm
+		 * @return the symmetric log value.
+		 */
+		public static function symLog(x:Number, b:Number) : Number
+        {
+            return x == 0 ? 0 : x > 0 ? log(x, b) : -log(-x, b);
+        }
+        
+        /**
+		 * Computes a zero-symmetric logarithm, with adjustment to values
+		 * between zero and the logarithm base. This adjustment introduces
+		 * distortion for values less than the base number, but enables
+		 * simultaneous plotting of log-transformed data involving both
+		 * positive and negative numbers.
+		 * @param x the number for which to compute the logarithm
+		 * @param b the base of the logarithm
+		 * @return the adjusted, symmetric log value.
+		 */
+        public static function adjLog(x:Number, b:Number) : Number
+        {
+        	var neg:Boolean = (x < 0);
+        	if (neg) x = -x;
+        	if (x < b) x += (b-x)/b;
+        	return neg ? -log(x,b) : log(x,b);
+        }
+        
+        /**
+         * Computes a zero-symmetric square root. Computes the square root of
+         * the absolute value of the input, and determines the sign of the
+         * output according to the sign of the input value.
+		 * @param x the number for which to compute the square root
+		 * @return the symmetric square root value.
+		 */
+		public static function symSqrt(x:Number) : Number
+		{
+			return (x > 0 ? Math.sqrt(x) : -Math.sqrt(-x));
+		}
+		
+		/**
+         * Computes a zero-symmetric Nth root. Computes the root of
+         * the absolute value of the input, and determines the sign of the
+         * output according to the sign of the input value.
+		 * @param x the number for which to compute the square root
+		 * @param p the root value (2 for square root, 3 for cubic root, etc)
+		 * @return the symmetric Nth root value.
+		 */
+		public static function symRoot(x:Number, p:Number) : Number
+		{
+			return (x > 0 ? Math.pow(x, 1/p) : -Math.pow(-x, 1/p));
+		}
+		
+		// -- Statistics ------------------------------------------------------
+		
+		/**
+         * Computes the n-quantile boundaries for a set of values.
+         * @param n the number of quantiles
+         * @param values the values to break into quantiles
+         * @param sort indicates if the values array needs to be sorted. If
+         *  true, the array will be sorted prior to determining quantile
+         *  boundaries. If false, the array must be in ascending sort order.
+         * @return an n-length array of quantile boundaries
+         */
+        public static function quantile(n:uint, values:Array, sort:Boolean):Array
+        {
+        	var len:uint = values.length-1;
+			var qtls:Array = new Array(n);
+			
+			if (sort) {
+            	values = Arrays.copy(values);
+            	values.sort(Array.NUMERIC);
+   			}
+   			
+            for (var i:uint=1; i <= n; ++i)
+            {
+                qtls[i-1] = values[uint((len*i)/n)];
+            }            
+            return qtls;
+        }
+		
+		
+		// -- Forward Interpolation Routines ----------------------------------
+		
+		/**
+		 * Computes a linear interpolation between two values.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param max the maximum value (corresponds to f==1)
+		 * @return the interpolated value
+		 */
+		public static function linearInterp(f:Number, min:Number, max:Number):Number
+		{
+			return min + f * (max - min);
+		}
+		
+		/**
+		 * Computes a logarithmic interpolation between two values. Uses a
+		 * zero-symmetric logarithm calculation (see <code>symLog</code>).
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param max the maximum value (corresponds to f==1)
+		 * @param b the base of the logarithm
+		 * @return the interpolated value
+		 */
+		public static function logInterp(f:Number, min:Number, max:Number, b:Number):Number
+		{
+			min = symLog(min, b); max = symLog(max, b);
+			f = min + f * (max - min);
+			return f<0 ? -Math.pow(b, -f) : Math.pow(b, f);
+		}
+		
+		/**
+		 * Computes a logarithmic interpolation between two values. Uses an
+		 * adjusted zero-symmetric logarithm calculation (see <code>adjLog</code>).
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param max the maximum value (corresponds to f==1)
+		 * @param b the base of the logarithm
+		 * @return the interpolated value
+		 */
+		public static function adjLogInterp(f:Number, min:Number, max:Number, b:Number):Number
+		{
+			min = adjLog(min, b); max = adjLog(max, b);
+			f = min + f * (max - min);
+			var neg:Boolean = f < 0;
+			f = neg ? Math.pow(b, -f) : Math.pow(b, f);
+			f = b*(f-1) / (b-1);
+			return neg ? -f : f;
+		}
+		
+		/**
+		 * Computes a square root interpolation between two values. Uses a
+		 * zero-symmetric root calculation (see <code>symSqrt</code>).
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param max the maximum value (corresponds to f==1)
+		 * @return the interpolated value
+		 */
+		public static function sqrtInterp(f:Number, min:Number, max:Number):Number
+		{
+			min = symSqrt(min); max = symSqrt(max);
+			f = min + f * (max - min);
+			return f<0 ? -(f*f) : f*f;
+		}
+		
+		/**
+		 * Computes an Nth-root interpolation between two values. Uses a
+		 * zero-symmetric root calculation (see <code>symRoot</code>).
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param max the maximum value (corresponds to f==1)
+		 * @param p the root value (2 for square root, 3 for cubic root, etc)
+		 * @return the interpolated value
+		 */
+		public static function rootInterp(f:Number, min:Number, max:Number, p:Number):Number
+		{
+			min = symRoot(min, p); max = symRoot(max, p);
+			f = min + f*(max - min);
+			var neg:Boolean = f < 0;
+			return neg ? -Math.pow(-f, p) : Math.pow(f, p);
+		}
+		
+		/**
+		 * Computes an interpolated value in a quantile scale.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 * @param quantiles an array of quantile boundaries
+		 * @return the interpolated value
+		 */
+		public static function quantileInterp(f:Number, quantiles:Array):Number
+		{
+			return quantiles[int(Math.round(f*(quantiles.length-1)))];
+		}
+		
+		
+		// -- Inverse Interpolation Routines ----------------------------------
+		
+		/**
+		 * Computes an inverse linear interpolation, returning an interpolation
+		 * fraction. Returns 0.5 if the min and max values are the same.
+		 * @param x the interpolated value
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param min the maximum value (corresponds to f==1)
+		 * @return the inferred interpolation fraction
+		 */
+        public static function invLinearInterp(x:Number, min:Number, max:Number):Number
+        {
+            var denom:Number = (max - min);
+            return (denom < EPSILON && denom > -EPSILON ? 0 : (x - min) / denom);
+        }
+        
+        /**
+		 * Computes an inverse logarithmic interpolation, returning an
+		 * interpolation fraction. Uses a zero-symmetric logarithm.
+		 * Returns 0.5 if the min and max values are the same.
+		 * @param x the interpolated value
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param min the maximum value (corresponds to f==1)
+		 * @param b the base of the logarithm
+		 * @return the inferred interpolation fraction
+		 */
+        public static function invLogInterp(x:Number, min:Number, max:Number, b:Number):Number
+        {
+            min = symLog(min, b);
+            var denom:Number = symLog(max, b) - min;
+            return (denom < EPSILON && denom > -EPSILON ? 0 : (symLog(x, b) - min) / denom);
+        }
+        
+        /**
+		 * Computes an inverse logarithmic interpolation, returning an
+		 * interpolation fraction. Uses an adjusted zero-symmetric logarithm.
+		 * Returns 0.5 if the min and max values are the same.
+		 * @param x the interpolated value
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param min the maximum value (corresponds to f==1)
+		 * @param b the base of the logarithm
+		 * @return the inferred interpolation fraction
+		 */
+        public static function invAdjLogInterp(x:Number, min:Number, max:Number, b:Number):Number
+        {
+            min = adjLog(min, b);
+            var denom:Number = adjLog(max, b) - min;
+            return (denom < EPSILON && denom > -EPSILON ? 0 : (adjLog(x, b) - min) / denom);
+        }
+        
+        /**
+		 * Computes an inverse square root interpolation, returning an
+		 * interpolation fraction. Uses a zero-symmetric square root.
+		 * Returns 0.5 if the min and max values are the same.
+		 * @param x the interpolated value
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param min the maximum value (corresponds to f==1)
+		 * @return the inferred interpolation fraction
+		 */
+        public static function invSqrtInterp(x:Number, min:Number, max:Number):Number
+        {
+            min = symSqrt(min);
+            var denom:Number = symSqrt(max) - min;
+            return (denom < EPSILON && denom > -EPSILON ? 0 : (symSqrt(x) - min) / denom);
+        }
+        
+        /**
+		 * Computes an inverse Nth-root interpolation, returning an
+		 * interpolation fraction. Uses a zero-symmetric root.
+		 * Returns 0.5 if the min and max values are the same.
+		 * @param x the interpolated value
+		 * @param min the minimum value (corresponds to f==0)
+		 * @param min the maximum value (corresponds to f==1)
+		 * @param p the root value (2 for square root, 3 for cubic root, etc)
+		 * @return the inferred interpolation fraction
+		 */
+        public static function invRootInterp(x:Number, min:Number, max:Number, p:Number):Number
+        {
+            min = symRoot(min,p);
+            var denom:Number = symRoot(max,p) - min;
+            return (denom < EPSILON  && denom > -EPSILON ? 0 : (symRoot(x,p) - min) / denom);
+        }
+
+		/**
+		 * Computes an inverse quantile scale interpolation, returning an
+		 * interpolation fraction.
+		 * @param x the interpolated value
+		 * @param quantiles an array of quantile boundaries
+		 * @return the inferred interpolation fraction
+		 */
+		public static function invQuantileInterp(x:Number, quantiles:/*Number*/Array):Number
+        {
+            var a:uint = 0, b:uint = quantiles.length;
+            var i:uint = b / 2;
+            while (a < b)
+            {   // binary search over the boundaries
+                if (quantiles[i] == x) {
+                	for (; i>0 && quantiles[i-1] == x; --i) null;
+                    break;
+                } else if (quantiles[i] < x) {
+                    a = i+1;
+                } else {
+                    b = i;
+                }
+                i = a + ((b - a) >> 1);
+            }
+            return Number(i) / (quantiles.length-1);
+        }
+        
+        // -- Perlin Noise ----------------------------------------------------
+        
+        /**
+         * Computes Perlin noise for a given (x, y, z) point.
+         * @param x the x parameter
+         * @param y the y parameter (default 0)
+         * @param z the z parameter (default 0)
+         * @return Perlin noise for the input co-ordinates
+         */
+        public static function noise(x:Number, y:Number=0, z:Number=0):Number
+   		{
+   			var X:int,Y:int,Z:int,A:int,AA:int,AB:int,B:int,BA:int,BB:int;
+   			var u:Number,v:Number,w:Number,a:Number,b:Number,c:Number,d:Number;
+   			var xx:Number, yy:Number, zz:Number;
+   			
+   			X = int(x); Y = int(y); Z = int(z);
+   			x -= X;     y -= Y;     z -= Z;
+   			X &= 255;   Y &= 255;   Z &= 255;
+   			xx = x-1;   yy = y-1;   zz = z-1;
+   			
+   			u = x * x * x * (x * (x*6 - 15) + 10);
+   			v = y * y * y * (y * (y*6 - 15) + 10);
+   			w = z * z * z * (z * (z*6 - 15) + 10);
+   			
+   			A  = (_p[X  ]+Y);
+   			AA = (_p[A  ]+Z);
+   			AB = (_p[A+1]+Z);
+   			B  = (_p[X+1]+Y);
+   			BA = (_p[B  ]+Z);
+   			BB = (_p[B+1]+Z);
+   			
+   			// interpolate
+   			a =       grad(_p[AA  ], x , y , z );
+   			b =       grad(_p[AB  ], x , yy, z );
+   			c =       grad(_p[AA+1], x , y , zz);
+   			d =       grad(_p[AB+1], x , yy, zz);
+   			a += u * (grad(_p[BA  ], xx, y , z ) - a);
+   			b += u * (grad(_p[BB  ], xx, yy, z ) - b);
+   			c += u * (grad(_p[BA+1], xx, y , zz) - c);
+   			d += u * (grad(_p[BB+1], xx, yy, zz) - d);
+   			a += v * (b - a);
+   			c += v * (d - c);
+   			return a + w * (c - a);
+   		}
+   		
+		private static function grad(h:int, x:Number, y:Number, z:Number):Number
+		{
+			h &= 15;
+			var u:Number = h<8 ? x : y;
+			var v:Number = h<4 ? y : h==2||h==14 ? x : z;
+			return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
+		}
+		
+		private static const _p:Array = [151,160,137,91,90,15,131,13,201,95,96,
+		53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21, 10,23,190, 6,148,
+		247,120,234,75, 0,26,197,62,94,252,219,203,117,35, 11, 32,57,177,33,88,
+		237,149,56,87,174, 20,125,136,171,168, 68,175,74,165, 71,134,139,48,27,
+		166,77,146,158,231,83,111,229,122, 60,211,133,230,220,105,92, 41,55,46,
+		245,40,244,102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208,89,
+		18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,
+		217,226,250,124,123, 5,202,38,147,118,126,255,82,85,212,207,206,59,227,
+		47,16,58,17,182,189,28,42,223,183,170,213,119,248,152, 2,44,154,163,70,
+		221,153,101,155,167, 43,172, 9,129,22,39,253, 19,98,108,110,79,113,224,
+		232,178,185, 112,104,218,246,97,228,251,34,242,193,238,210,144, 12,191,
+		179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,
+		184,84,204,176,115,121,50,45,127, 4,150,254,138,236,205,93,222,114, 67,
+		29,24,72,243,141,128,195,78,66,215,61,156,180,// now we repeat the list
+		151,160,137,91,90,15,131, 13,201,95,96,53,194,233, 7,225,140,36,103,30,
+		69,142,8,99,37,240,21, 10,23,190, 6,148,247,120,234,75, 0,26,197,62,94,
+		252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,
+		168, 68,175,74,165,71,134,139,48, 27,166,77,146,158,231,83,111,229,122,
+		60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54, 65,25,63,161,
+		1,216, 80,73,209,76,132,187,208, 89,18,169,200,196,135,130,116,188,159,
+		86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 5,202, 38,147,
+		118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,
+		170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167,43,172,9,129,
+		22,39,253, 19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,
+	   	251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,
+	   	107,49,192,214, 31,181,199,106,157,184,84,204,176,115,121,50,45,127, 4,
+	   	150,254,138,236,205,93,222,114,67,29, 24,72,243,141,128,195, 78,66,215,
+	   	61,156,180];
+
+	} // end of class Maths
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Shapes.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Shapes.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Shapes.as	(revision 15)
@@ -0,0 +1,551 @@
+package gssim.gssimstudio.editor.flare.util
+{	
+	import flash.display.Graphics;
+	
+	/**
+	 * Utility class defining shape types and shape drawing routines. All shape
+	 * drawing functions take two arguments: a <code>Graphics</code> context
+	 * to draw with and a size parameter determining the radius of the shape
+	 * (i.e., the height and width of the shape are twice the size parameter).
+	 * 
+	 * <p>All shapes are indicated by a name. This class registers these names
+	 * with drawing functions, allowing the lookup of shape rendering routines
+	 * by the shapes name. For example, these shape names may be assigned using
+	 * a <code>flare.vis.operator.encoder.ShapeEncoder</code> and then later
+	 * rendered by looking up the shape with this class, as done by the
+	 * <code>flare.vis.data.render.ShapeRenderer</code> class. The set of 
+	 * available shapes can be extended by using the static
+	 * <code>setShape</code> method to register a new shape name and
+	 * drawing function.</p>
+	 */
+	public class Shapes
+	{
+		/** Constant indicating a straight line shape. */
+		public static const LINE:String = "line";
+		/** Constant indicating a Bezier curve. */
+		public static const BEZIER:String = "bezier";
+		/** Constant indicating a cardinal spline. */
+		public static const CARDINAL:String = "cardinal";
+		/** Constant indicating a B-spline. */
+		public static const BSPLINE:String = "bspline";
+		
+		/** Constant indicating a rectangular block shape. */
+		public static const BLOCK:String = "block";
+		/** Constant indicating a polygon shape. */
+		public static const POLYGON:String = "polygon";
+		/** Constant indicating a "polyblob" shape, a polygon whose
+		 *  edges are interpolated with a cardinal spline. */
+		public static const POLYBLOB:String = "polyblob";
+		/** Constant indicating a vertical bar shape. */
+		public static const VERTICAL_BAR:String = "verticalBar";
+		/** Constant indicating a horizontal bar shape. */
+		public static const HORIZONTAL_BAR:String = "horizontalBar";
+		/** Constant indicating a wedge shape. */
+		public static const WEDGE:String = "wedge";
+		
+		/** Constant indicating a circle shape. */
+		public static const CIRCLE:String = "circle";
+		/** Constant indicating a square shape. */
+		public static const SQUARE:String = "square";
+		/** Constant indicating a cross shape. */
+		public static const CROSS:String = "cross";
+		/** Constant indicating an 'X' shape. */
+		public static const X:String = "x";
+		/** Constant indicating a diamond shape. */
+		public static const DIAMOND:String = "diamond";
+		/** Constant indicating a upward-pointing triangle shape. */
+		public static const TRIANGLE_UP:String = "triangleUp";
+		/** Constant indicating a downward-pointing triangle shape. */
+		public static const TRIANGLE_DOWN:String = "triangleDown";
+		/** Constant indicating a rightward-pointing triangle shape. */
+		public static const TRIANGLE_RIGHT:String = "triangleRight";
+		/** Constant indicating a leftward-pointing triangle shape. */
+		public static const TRIANGLE_LEFT:String = "triangleLeft";
+		
+		private static var _shapes:Object = {
+			circle: drawCircle,
+			square: drawSquare,
+			cross: drawCross,
+			x: drawX,
+			diamond: drawDiamond,
+			triangleUp: drawTriangleUp,
+			triangleDown: drawTriangleDown,
+			triangleRight: drawTriangleRight,
+			triangleLeft: drawTriangleLeft
+		};
+		
+		/**
+		 * Gets the shape drawing function with the given name. 
+		 * @param name the name of the shape to draw
+		 * @return a function for drawing the shape or null if the shape name
+		 *  is not found. The returned function takes two parameters:
+		 *  a graphics object and a numerical size value. The size value
+		 *  indicates the radius of the shape.
+		 */
+		public static function getShape(name:String):Function
+		{
+			return _shapes[name];
+		}
+		
+		/**
+		 * Sets the shape drawing function for a given shape name. 
+		 * @param name the name of the shape to draw
+		 * @param draw a function for drawing the shape. This function must
+		 *  take two parameters: a graphics object and a numerical size value.
+		 *  The size value indicates the radius of the shape.
+		 */
+		public static function setShape(name:String, draw:Function):void
+		{
+			_shapes[name] = draw;
+		}
+		
+		/**
+		 * Resets all shape drawing functions to the default settings. 
+		 */
+		public static function resetShapes():void
+		{
+			_shapes = {
+				circle: drawCircle,
+				square: drawSquare,
+				cross: drawCross,
+				x: drawX,
+				diamond: drawDiamond,
+				triangleUp: drawTriangleUp,
+				triangleDown: drawTriangleDown,
+				triangleRight: drawTriangleRight,
+				triangleLeft: drawTriangleLeft
+			};
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Draws a circle shape.
+		 * @param g the graphics context to draw with
+		 * @param size the radius of the circle
+		 */
+		public static function drawCircle(g:Graphics, size:Number):void
+		{
+			g.drawCircle(0, 0, size);
+		}
+		
+		/**
+		 * Draws a square shape.
+		 * @param g the graphics context to draw with
+		 * @param size the (half-)size of the square. The height and width of
+		 *  the shape will both be exactly twice the size parameter.
+		 */
+		public static function drawSquare(g:Graphics, size:Number):void
+		{
+			g.drawRect(-size, -size, 2*size, 2*size);
+		}
+		
+		/**
+		 * Draws a cross shape.
+		 * @param g the graphics context to draw with
+		 * @param size the (half-)size of the cross. The height and width of
+		 *  the shape will both be exactly twice the size parameter.
+		 */
+		public static function drawCross(g:Graphics, size:Number):void
+		{
+			g.moveTo(0, -size);
+			g.lineTo(0, size);
+			g.moveTo(-size, 0);
+			g.lineTo(size, 0);
+		}
+		
+		/**
+		 * Draws an "x" shape.
+		 * @param g the graphics context to draw with
+		 * @param size the (half-)size of the "x". The height and width of
+		 *  the shape will both be exactly twice the size parameter.
+		 */
+		public static function drawX(g:Graphics, size:Number):void
+		{
+			g.moveTo(-size, -size);
+			g.lineTo(size, size);
+			g.moveTo(size, -size);
+			g.lineTo(-size, size);
+		}
+		
+		/**
+		 * Draws a diamond shape.
+		 * @param g the graphics context to draw with
+		 * @param size the (half-)size of the diamond. The height and width of
+		 *  the shape will both be exactly twice the size parameter.
+		 */
+		public static function drawDiamond(g:Graphics, size:Number):void
+		{
+			g.moveTo(0, size);
+			g.lineTo(-size, 0);
+			g.lineTo(0, -size);
+			g.lineTo(size, 0);
+			g.lineTo(0, size);	
+		}
+		
+		/**
+		 * Draws an upward-pointing triangle shape.
+		 * @param g the graphics context to draw with
+		 * @param size the (half-)size of the triangle. The height and width of
+		 *  the shape will both be exactly twice the size parameter.
+		 */
+		public static function drawTriangleUp(g:Graphics, size:Number):void
+		{
+			g.moveTo(-size, size);
+			g.lineTo(size, size);
+			g.lineTo(0, -size);
+			g.lineTo(-size, size);
+		}
+		
+		/**
+		 * Draws a downward-pointing triangle shape.
+		 * @param g the graphics context to draw with
+		 * @param size the (half-)size of the triangle. The height and width of
+		 *  the shape will both be exactly twice the size parameter.
+		 */
+		public static function drawTriangleDown(g:Graphics, size:Number):void
+		{
+			g.moveTo(-size, -size);
+			g.lineTo(size, -size);
+			g.lineTo(0, size);
+			g.lineTo(-size, -size);
+		}
+		
+		/**
+		 * Draws a right-pointing triangle shape.
+		 * @param g the graphics context to draw with
+		 * @param size the (half-)size of the triangle. The height and width of
+		 *  the shape will both be exactly twice the size parameter.
+		 */
+		public static function drawTriangleRight(g:Graphics, size:Number):void
+		{
+			g.moveTo(-size, -size);
+			g.lineTo(size, 0);
+			g.lineTo(-size, size);
+			g.lineTo(-size, -size);
+		}
+		
+		/**
+		 * Draws a left-pointing triangle shape.
+		 * @param g the graphics context to draw with
+		 * @param size the (half-)size of the triangle. The height and width of
+		 *  the shape will both be exactly twice the size parameter.
+		 */
+		public static function drawTriangleLeft(g:Graphics, size:Number):void
+		{
+			g.moveTo(size, -size);
+			g.lineTo(-size, 0);
+			g.lineTo(size, size);
+			g.lineTo(size, -size);
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Draws an arc (a segment of a circle's circumference)
+		 * @param g the graphics context to draw with
+		 * @param x the center x-coordinate of the arc
+		 * @param y the center y-coorindate of the arc
+		 * @param radius the radius of the arc
+		 * @param a0 the starting angle of the arc (in radians)
+		 * @param a1 the ending angle of the arc (in radians)
+		 */
+		public static function drawArc(g:Graphics, x:Number, y:Number, 
+									radius:Number, a0:Number, a1:Number) : void
+		{
+			var slices:Number = (Math.abs(a1-a0) * radius) / 4;
+			var a:Number, cx:Number = x, cy:Number = y;
+			
+			for (var i:uint = 0; i <= slices; ++i) {
+				a = a0 + i*(a1-a0)/slices;
+				x = cx + radius * Math.cos(a);
+				y = cy + -radius * Math.sin(a);
+				if (i==0) {
+					g.moveTo(x, y);
+				} else {
+					g.lineTo(x,y);
+				}
+			}
+		}
+		
+		/**
+		 * Draws a wedge defined by an angular range and inner and outer radii.
+		 * An inner radius of zero results in a pie-slice shape.
+		 * @param g the graphics context to draw with
+		 * @param x the center x-coordinate of the wedge
+		 * @param y the center y-coorindate of the wedge
+		 * @param outer the outer radius of the wedge
+		 * @param inner the inner radius of the wedge
+		 * @param a0 the starting angle of the wedge (in radians)
+		 * @param a1 the ending angle of the wedge (in radians)
+		 */
+		public static function drawWedge(g:Graphics, x:Number, y:Number, 
+			outer:Number, inner:Number, a0:Number, a1:Number) : void
+		{
+			var a:Number = Math.abs(a1-a0);
+			var slices:int = Math.max(4, int(a * outer / 6));
+			var cx:Number = x, cy:Number = y, x0:Number, y0:Number;
+			var circle:Boolean = (a >= 2*Math.PI - 0.001);
+
+			if (slices <= 0) return;
+		
+			// pick starting point
+			if (inner <= 0 && !circle) {
+				g.moveTo(cx, cy);
+			} else {
+				x0 = cx + outer * Math.cos(a0);
+				y0 = cy + -outer * Math.sin(a0);
+				g.moveTo(x0, y0);
+			}
+			
+			// draw outer arc
+			for (var i:uint = 0; i <= slices; ++i) {
+				a = a0 + i*(a1-a0)/slices;
+				x = cx + outer * Math.cos(a);
+				y = cy + -outer * Math.sin(a);
+				g.lineTo(x,y);
+			}
+
+			if (circle) {
+				// return to starting point
+				g.lineTo(x0, y0);
+			} else if (inner > 0) {
+				// draw inner arc
+				for (i = slices+1; --i >= 0;) {
+					a = a0 + i*(a1-a0)/slices;
+					x = cx + inner * Math.cos(a);
+					y = cy + -inner * Math.sin(a);
+					g.lineTo(x,y);
+				}
+				g.lineTo(x0, y0);
+			} else {
+				// return to center
+				g.lineTo(cx, cy);
+			}
+		}
+		
+		/**
+		 * Draws a polygon shape.
+		 * @param g the graphics context to draw with
+		 * @param a a flat array of x, y values defining the polygon
+		 */
+		public static function drawPolygon(g:Graphics, a:Array) : void
+		{
+			g.moveTo(a[0], a[1]);
+			for (var i:uint=2; i<a.length; i+=2) {
+				g.lineTo(a[i], a[i+1]);
+			}
+			g.lineTo(a[0], a[1]);
+		}
+		
+		/**
+		 * Draws a cubic Bezier curve.
+		 * @param g the graphics context to draw with
+		 * @param ax x-coordinate of the starting point
+		 * @param ay y-coordinate of the starting point
+		 * @param bx x-coordinate of the first control point
+		 * @param by y-coordinate of the first control point
+		 * @param cx x-coordinate of the second control point
+		 * @param cy y-coordinate of the second control point
+		 * @param dx x-coordinate of the ending point
+		 * @param dy y-coordinate of the ending point
+		 * @param move if true (the default), the graphics context will be
+		 *  moved to the starting point before drawing starts. If false,
+		 *  no move command will be issued; this is useful when connecting
+		 *  multiple curves to define a filled region.
+		 */
+		public static function drawCubic(g:Graphics, ax:Number, ay:Number,
+			bx:Number, by:Number, cx:Number, cy:Number, dx:Number, dy:Number,
+			move:Boolean=true) : void
+		{			
+			var subdiv:int, u:Number, xx:Number, yy:Number;			
+			
+			// determine number of line segments
+			subdiv = int((Math.sqrt((xx=(bx-ax))*xx + (yy=(by-ay))*yy) +
+					      Math.sqrt((xx=(cx-bx))*xx + (yy=(cy-by))*yy) +
+					      Math.sqrt((xx=(dx-cx))*xx + (yy=(dy-cy))*yy)) / 4);
+			if (subdiv < 1) subdiv = 1;
+
+			// compute Bezier co-efficients
+			var c3x:Number = 3 * (bx - ax);
+            var c2x:Number = 3 * (cx - bx) - c3x;
+            var c1x:Number = dx - ax - c3x - c2x;
+            var c3y:Number = 3 * (by - ay);
+            var c2y:Number = 3 * (cy - by) - c3y;
+            var c1y:Number = dy - ay - c3y - c2y;
+			
+			if (move) g.moveTo(ax, ay);
+			for (var i:uint=0; i<=subdiv; ++i) {
+				u = i/subdiv;
+				xx = u*(c3x + u*(c2x + u*c1x)) + ax;
+				yy = u*(c3y + u*(c2y + u*c1y)) + ay;
+				g.lineTo(xx, yy);
+			}
+		}
+		
+		// -- BSpline rendering state variables --
+		private static var _knot:Array  = new Array(20);
+		private static var _basis:Array = new Array(36);
+
+		/**
+		 * Draws a cubic open uniform B-spline. The spline passes through the
+		 * first and last control points, but not necessarily any others.
+		 * @param g the graphics context to draw with
+		 * @param p an array of points defining the spline control points
+		 * @param slack a slack parameter determining the "tightness" of the
+		 *  spline. At value 1 (the default) a normal b-spline will be drawn,
+		 *  at value 0 a straight line between the first and last points will
+		 *  be drawn. Intermediate values interpolate smoothly between these
+		 *  two extremes.
+		 * @param move if true (the default), the graphics context will be
+		 *  moved to the starting point before drawing starts. If false,
+		 *  no move command will be issued; this is useful when connecting
+		 *  multiple curves to define a filled region.
+		 */
+		public static function drawBSpline(g:Graphics, p:Array, npts:int=-1,
+			move:Boolean=true):void
+		{
+			var N:int = (npts < 0 ? p.length/2 : npts);
+			var k:int = N<4 ? 3 : 4, nplusk:int = N+k;
+			var i:int, j:int, s:int, subdiv:int = 40;
+			var x:Number, y:Number, step:Number, u:Number;
+			
+			// if only two points, draw a line between them
+			if (N==2) {
+				if (move) g.moveTo(p[0],p[1]);
+				g.lineTo(p[2],p[3]);
+				return;
+			}
+			
+			// initialize knot vector
+			for (i=1, _knot[0]=0; i<nplusk; ++i) {
+				_knot[i] = _knot[i-1] + (i>=k && i<=N ? 1 : 0);
+			}
+			
+			// calculate the points on the bspline curve
+			step = _knot[nplusk-1] / subdiv;
+			for (s=0; s <= subdiv; ++s) {
+				u = step * s;
+				
+				// calculate basis function -----
+				for (i=0; i < nplusk-1; ++i) { // first-order
+					_basis[i] = (u >= _knot[i] && u < _knot[i+1] ? 1 : 0);
+				}
+				for (j=2; j <= k; ++j) { // higher-order
+					for (i=0; i < nplusk-j; ++i) {
+						x = (_basis[i  ]==0 ? 0 : ((u-_knot[i])*_basis[i]) / (_knot[i+j-1]-_knot[i]));
+						y = (_basis[i+1]==0 ? 0 : ((_knot[i+j]-u)*_basis[i+1]) / (_knot[i+j]-_knot[i+1]));
+						_basis[i] = x + y;
+					}
+				}
+				if (u == _knot[nplusk-1]) _basis[N-1] = 1; // last point
+				
+				// interpolate b-spline point -----
+				for (i=0, j=0, x=0, y=0; i<N; ++i, j+=2) {
+					x += _basis[i] * p[j];
+					y += _basis[i] * p[j+1];
+				}
+				if (s==0) {
+					if (move) g.moveTo(x, y);
+				} else {
+					g.lineTo(x, y);
+				}
+			}
+		}
+		
+		/**
+		 * Draws a cardinal spline composed of piecewise connected cubic
+		 * Bezier curves. Curve control points are inferred so as to ensure
+		 * C1 continuity (continuous derivative).
+		 * @param g the graphics context to draw with
+		 * @param p an array defining a polygon or polyline to render with a
+		 *  cardinal spline
+		 * @param s a tension parameter determining the spline's "tightness"
+		 * @param closed indicates if the cardinal spline should be a closed
+		 *  shape. False by default.
+		 */
+		public static function drawCardinal(g:Graphics, p:Array, npts:int=-1,
+			s:Number=0.15, closed:Boolean=false) : void
+		{
+			// compute the size of the path
+	        var len:uint = (npts < 0 ? p.length : 2*npts);
+	        
+	        if (len < 6)
+	            throw new Error("Cardinal splines require at least 3 points");
+	        
+	        var dx1:Number, dy1:Number, dx2:Number, dy2:Number;
+	        g.moveTo(p[0], p[1]);
+	        
+	        // compute first control points
+	        if (closed) {
+	            dx2 = p[2]-p[len-2];
+	            dy2 = p[3]-p[len-1];
+	        } else {
+	            dx2 = p[4]-p[0]
+	            dy2 = p[5]-p[1];
+	        }
+
+	        // iterate through control points
+	        var i:uint = 0;
+	        for (i=2; i<len-2; i+=2) {
+	            dx1 = dx2; dy1 = dy2;
+	            dx2 = p[i+2] - p[i-2];
+	            dy2 = p[i+3] - p[i-1];
+	            
+	            drawCubic(g, p[i-2],    p[i-1],
+						     p[i-2]+s*dx1, p[i-1]+s*dy1,
+	                         p[i]  -s*dx2, p[i+1]-s*dy2,
+	                         p[i],         p[i+1], false);
+	        }
+	        
+	        // finish spline
+	        if (closed) {
+	            dx1 = dx2; dy1 = dy2;
+	            dx2 = p[0] - p[i-2];
+	            dy2 = p[1] - p[i-1];
+	            drawCubic(g, p[i-2], p[i-1], p[i-2]+s*dx1, p[i-1]+s*dy1,
+	            			 p[i]-s*dx2, p[i+1]-s*dy2, p[i], p[i+1], false);
+	            
+	            dx1 = dx2; dy1 = dy2;
+	            dx2 = p[2] - p[len-2];
+	            dy2 = p[3] - p[len-1];
+	            drawCubic(g, p[len-2], p[len-1], p[len-2]+s*dx1, p[len-1]+s*dy1,
+	            	p[0]-s*dx2, p[1]-s*dy2, p[0], p[1], false);
+	        } else {
+	        	drawCubic(g, p[i-2], p[i-1], p[i-2]+s*dx1, p[i-1]+s*dy1,
+	        		p[i]-s*dx2, p[i+1]-s*dy2, p[i], p[i+1], false);
+	        }
+		}
+		
+		/**
+		 * A helper function for consolidating end points and control points
+		 * for a spline into a single array.
+		 * @param x1 the x-coordinate for the first end point
+		 * @param y1 the y-coordinate for the first end point
+		 * @param controlPoints an array of control points
+		 * @param x2 the x-coordinate for the second end point
+		 * @param y2 the y-coordinate for the second end point
+		 * @param p the array in which to store the consolidated points.
+		 *  If null, a new array will be created and returned.
+		 * @return the consolidated array of all points
+		 */
+		public static function consolidate(x1:Number, y1:Number,
+			controlPoints:Array, x2:Number, y2:Number, p:Array=null):Array
+		{
+			var len:int = 4 + controlPoints.length;
+			if (!p) {
+				p = new Array(len);
+			} else {
+				while (p.length < len) p.push(0);
+			}
+			
+			Arrays.copy(controlPoints, p, 0, 2);
+			p[0] = x1;
+			p[1] = y1;
+			p[len-2] = x2;
+			p[len-1] = y2;
+			return p;
+		}
+		
+	} // end of class Shapes
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Property.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Property.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Property.as	(revision 15)
@@ -0,0 +1,206 @@
+package gssim.gssimstudio.editor.flare.util
+{		
+	/**
+	 * Utility class for accessing arbitrary property chains, allowing
+	 * nested property expressions (e.g., <code>x.a.b.c</code> or 
+	 * <code>x.a[1]</code>). To reduce initialization times, this class also
+	 * maintains a static cache of all Property instances created using the
+	 * static <code>$()</code> method.
+	 */
+	public class Property implements IEvaluable, IPredicate
+	{
+		private static const DELIMITER:* = /[\.|\[(.*)\]]/;
+		
+		private static var __cache:Object = {};
+		private static var __stack:Array = [];
+		private static var __proxy:IValueProxy;
+
+		/**
+		 * Requests a Property instance for the given property name. This is a
+		 * factory method that caches and reuses property instances, saving
+		 * memory and construction time. This method is the preferred way of
+		 * getting a property and should be used instead of the constructor.
+		 * @param name the name of the property
+		 * @return the requested property instance
+		 */
+		public static function $(name:String):Property
+		{
+			if (name == null) return null;
+			var p:Property = __cache[name];
+			if (p == null) {
+				p = new Property(name);
+				__cache[name] = p;
+			}
+			return p;
+		}
+		
+		/**
+		 * Clears the cache of created Property instances
+		 */
+		public static function clearCache():void
+		{
+			__cache = {};
+		}
+
+		/** A minimal <code>IValueProxy</code> instance that gets and sets
+		 *  property values through <code>Property</code> instances. */
+		public static function get proxy():IValueProxy {
+			if (__proxy == null) __proxy = new PropertyProxy();
+			return __proxy;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		private var _field:String;
+		private var _chain:Array;
+		
+		/** The property name string. */
+		public function get name():String { return _field; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new Property, in most cases the static <code>$</code>
+		 * method should be used instead of this constructor.
+		 * @param name the property name string
+		 */
+		public function Property(name:String) {
+			if (name == null) {
+				throw new ArgumentError("Not a valid property name: "+name);
+			}
+			
+			_field = name;
+			_chain = null;
+			
+			if (_field != null) {
+				var parts:Array = _field.split(DELIMITER);
+				if (parts.length > 1) {
+					_chain = [];
+					for (var i:int=0; i<parts.length; ++i) {
+						if (parts[i].length > 0)
+							_chain.push(parts[i]);
+					}
+				}
+			}
+		}
+		
+		/**
+		 * Gets the value of this property for the input object.
+		 * @param x the object to retrieve the property value for
+		 * @return the property value
+		 */
+		public function getValue(x:Object):*
+		{
+			if (x == null) {
+				return null;
+			} else if (_chain == null) {
+				return x[_field];
+			} else {
+				for (var i:uint=0; i<_chain.length; ++i) {
+					x = x[_chain[i]];
+				}
+				return x;
+			}
+		}
+		
+		/**
+		 * Gets the value of this property for the input object; this
+		 * is the same as <code>getValue</code>, but provided in order to
+		 * implement the <code>IEvaluable</code> interface.
+		 * @param x the object to retrieve the property value for
+		 * @return the property value
+		 */
+		public function eval(x:Object=null):*
+		{
+			if (x == null) {
+				return null;
+			} else if (_chain == null) {
+				return x[_field];
+			} else {
+				for (var i:uint=0; i<_chain.length; ++i) {
+					x = x[_chain[i]];
+				}
+				return x;
+			}
+		}
+		
+		/**
+		 * Gets the value of this property and casts the result to a
+		 * Boolean value.
+		 * @param x the object to retrieve the property value for
+		 * @return the property value as a Boolean
+		 */
+		public function predicate(x:Object):Boolean
+		{
+			return Boolean(eval(x));
+		}
+		
+		/**
+		 * Sets the value of this property for the input object. If the reset
+		 * flag is true, all properties along a property chain will be updated.
+		 * Otherwise, only the last property in the chain is updated.
+		 * @param x the object to set the property value for
+		 * @param val the value to set
+		 */
+		public function setValue(x:Object, val:*):void
+		{
+			if (_chain == null) {
+				x[_field] = val;
+			} else {
+				__stack.push(x);
+				for (var i:uint=0; i<_chain.length-1; ++i) {
+					__stack.push(x = x[_chain[i]]);	
+				}
+				
+				var p:Object = __stack.pop();
+				p[_chain[i]] = val;
+				
+				for (i=_chain.length-1; --i >= 0; ) {
+					x = p;
+					p = __stack.pop();
+					try {
+						p[_chain[i]] = x;
+					} catch (err:Error) {}
+				}
+			}
+		}
+		
+		/**
+		 * Deletes a dynamically-bound property from an object.
+		 * @param x the object from which to delete the property
+		 */
+		public function deleteValue(x:Object):void
+		{
+			if (_chain == null) {
+				delete x[_field];
+			} else {
+				for (var i:uint=0; i<_chain.length-1; ++i) {
+					x = x[_chain[i]];
+				}
+				delete x[_chain[i]];
+			}
+		}
+		
+	} // end of class Property
+}
+
+import gssim.gssimstudio.editor.flare.util.IValueProxy;
+import gssim.gssimstudio.editor.flare.util.Property;
+
+/** A simple value proxy that uses Property instances to set and
+ *  get values for input objects. */
+class PropertyProxy implements IValueProxy
+{
+	public function setValue(o:Object, name:String, value:*):void
+	{
+		Property.$(name).setValue(o, value);
+	}
+	public function getValue(o:Object, name:String):*
+	{
+		return Property.$(name).getValue(o);
+	}
+	public function $(o:Object):Object
+	{
+		return o;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Filter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Filter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Filter.as	(revision 15)
@@ -0,0 +1,68 @@
+package gssim.gssimstudio.editor.flare.util
+{	
+	/**
+	 * Utility methods for creating filter functions. The static
+	 * <code>$()</code> method takes an arbitrary object and generates a
+	 * corresponding filter function.
+	 * 
+	 * <p>Filter functions are functions that take one argument and return a
+	 * <code>Boolean</code> value. The input argument to a filter function
+	 * passes the filter if the function returns true and fails the
+	 * filter if the function returns false.</p>
+	 */
+	public class Filter
+	{
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function Filter()
+		{
+			throw new Error("This is an abstract class.");
+		}
+		
+		/**
+		 * Convenience method that returns a filter function determined by the
+		 * input object.
+		 * <ul>
+		 *  <li>If the input is null or a <code>Function</code>, it is simply
+		 *      returned.</li>
+		 *  <li>If the input is an <code>IPredicate</code>, its
+		 *      <code>predicate</code> function is returned.</li>
+		 *  <li>If the input is a <code>String</code>, a <code>Property</code>
+		 *      instance with the string as the property name is generated, and
+		 *      the <code>predicate</code> function of the property is
+		 *      returned.</li>
+		 *  <li>If the input is a <code>Class</code> instance, a function that
+		 *      performs type-checking for that class type is returned.</li>
+		 *  <li>In any other case, an error is thrown.</li>
+		 * </ul>
+		 * @param f an input object specifying the filter criteria
+		 * @return the filter function
+		 */
+		public static function $(f:*):Function
+		{
+			if (f==null || f is Function) {
+				return f;
+			} else if (f is IPredicate) {
+				return IPredicate(f).predicate;
+			} else if (f is String) {
+				return Property.$(f).predicate;
+			} else if (f is Class) {
+				return typeChecker(Class(f));
+			} else {
+				throw new ArgumentError("Unrecognized filter type");
+			}
+		}
+		
+		/**
+		 * Returns a filter function that performs type-checking. 
+		 * @param type the <code>Class</code> type to check for
+		 * @return a <code>Boolean</code>-valued type checking filter function
+		 */
+		public static function typeChecker(type:Class):Function
+		{
+			return function(o:Object):Boolean { return o is type; }
+		}
+
+	} // end of class Filter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/IMatrix.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/IMatrix.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/IMatrix.as	(revision 15)
@@ -0,0 +1,89 @@
+package gssim.gssimstudio.editor.flare.util.math
+{
+	/**
+	 * Interface for a matrix of real-valued numbers.
+	 */
+	public interface IMatrix
+	{
+		/** The number of rows. */
+		function get rows():int;
+		/** The number of columns. */
+		function get cols():int;
+		/** The number of non-zero values. */
+		function get nnz():int;
+		/** The sum of all the entries in this matrix. */
+		function get sum():Number;
+		/** The sum of squares of all the entries in this matrix. */
+		function get sumsq():Number;
+		
+		/** Creates a copy of this matrix. */
+		function clone():IMatrix;
+		
+		/**
+		 * Creates a new matrix of the same type.
+		 * @param rows the number of rows in the new matrix
+		 * @param cols the number of columns in the new matrix
+		 * @return a new matrix
+		 */
+		function like(rows:int, cols:int):IMatrix;
+		
+		/** 
+		 * Initializes the matrix to desired dimensions. This method also
+		 * resets all values in the matrix to zero.
+		 * @param rows the number of rows in this matrix
+		 * @param cols the number of columns in this matrix
+		 */
+		function init(rows:int, cols:int):void;
+		
+		/**
+		 * Returns the value at the given indices. 
+		 * @param i the row index
+		 * @param j the column index
+		 * @return the value at position i,j
+		 */
+		function get(i:int, j:int):Number;
+		
+		/**
+		 * Sets the value at the given indices. 
+		 * @param i the row index
+		 * @param j the column index
+		 * @param v the value to set
+		 * @return the input value v
+		 */
+		function set(i:int, j:int, v:Number):Number;
+		
+		/**
+		 * Multiplies all values in this matrix by the input scalar.
+		 * @param s the scalar to multiply by.
+		 */
+		function scale(s:Number):void;
+		
+		/**
+		 * Multiplies this matrix by another. The number of rows in this matrix
+		 * must match the number of columns in the input matrix.
+		 * @param b the matrix to multiply by.
+		 * @return a new matrix that is the product of this matrix with the
+		 *  input matrix. The new matrix will be of the same type as this one.
+		 */
+		function multiply(b:IMatrix):IMatrix;
+		
+		/**
+		 * Visit all non-zero values in the matrix.
+		 * The input function is expected to take three arguments--the row
+		 * index, the column index, and the cell value--and return a number
+		 * which then becomes the new value for the cell.
+		 * @param f the function to invoke for each non-zero value
+		 */
+		function visitNonZero(f:Function):void;
+		
+		/**
+		 * Visit all values in the matrix.
+		 * The input function is expected to take three arguments--the row
+		 * index, the column index, and the cell value--and return a number
+		 * which then becomes the new value for the cell.
+		 * @param f the function to invoke for each value
+		 */
+		function visit(f:Function):void;
+		
+	} // end of interface IMatrix
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/SparseMatrix.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/SparseMatrix.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/SparseMatrix.as	(revision 15)
@@ -0,0 +1,151 @@
+package gssim.gssimstudio.editor.flare.util.math
+{
+	import flash.utils.Dictionary;
+	
+	/**
+	 * A matrix of numbers implemented using a hashtable of values.
+	 */
+	public class SparseMatrix implements IMatrix
+	{
+		private var _r:int;
+		private var _c:int;
+		private var _nnz:int;
+		private var _v:Dictionary;
+		
+		/** @inheritDoc */
+		public function get rows():int { return _r; }
+		/** @inheritDoc */
+		public function get cols():int { return _c; }
+		/** @inheritDoc */
+		public function get nnz():int {
+			var count:int = 0;
+			for (var key:String in _v)
+				++count;
+			return count;
+		}
+		/** @inheritDoc */
+		public function get sum():Number {
+			var sum:Number = 0;
+			for (var key:String in _v)
+				sum += _v[key];
+			return sum;
+		}
+		/** @inheritDoc */
+		public function get sumsq():Number {
+			var sumsq:Number = 0, v:Number;
+			for (var key:String in _v) {
+				v = _v[key];
+				sumsq += v*v;
+			}
+			return sumsq;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new SparseMatrix with the given size. 
+		 * @param rows the number of rows
+		 * @param cols the number of columns
+		 */
+		public function SparseMatrix(rows:int, cols:int) {
+			init(rows, cols);
+		}
+		
+		/** @inheritDoc */
+		public function clone():IMatrix {
+			var m:SparseMatrix = new SparseMatrix(_r, _c);
+			for (var key:String in _v)
+				m._v[key] = _v[key];
+			return m;
+		}
+		
+		/** @inheritDoc */
+		public function like(rows:int, cols:int):IMatrix {
+			return new SparseMatrix(rows, cols);
+		}
+		
+		/** @inheritDoc */
+		public function init(rows:int, cols:int):void {
+			_r = rows;
+			_c = cols;
+			_nnz = 0;
+			_v = new Dictionary();
+		}
+		
+		/** @inheritDoc */
+		public function get(i:int, j:int):Number {
+			var v:* = _v[i*_c + j];
+			return (v ? Number(v) : 0);
+		}
+		
+		/** @inheritDoc */
+		public function set(i:int, j:int, v:Number):Number {
+			var key:int = i*_c + j;
+			if (v==0) {
+				delete _v[key];
+			} else {
+				_v[key] = v;
+			}
+			return v;
+		}
+		
+		/** @inheritDoc */
+		public function scale(s:Number):void {
+			for (var key:String in _v) _v[key] *= s;
+		}
+		
+		/** @inheritDoc */
+		public function multiply(b:IMatrix):IMatrix {
+			if (cols != b.rows)
+				throw new Error("Incompatible matrix dimensions.");
+			var z:IMatrix = like(rows, b.cols);
+			for (var i:uint=0; i<z.rows; ++i) {
+				for (var j:uint=0; j<z.cols; ++j) {
+					var v:Number = 0;
+					for (var k:uint=0; k<cols; ++k)
+						v += get(i,k) * b.get(k,j);
+					if (v != 0)
+						z.set(i, j, v);
+				}
+			}
+			return z;
+		}
+		
+		/** @inheritDoc */
+		public function visitNonZero(f:Function):void {
+			var i:int, j:int, k:int, v:Number;
+			for (var key:String in _v) {
+				k = int(key);
+				i = k / _c;
+				j = k % _c;
+				v = _v[k];
+				v = f(i,j,v);
+				if (v==0) {
+					delete _v[key];
+				} else {
+					_v[key] = v;
+				}
+			}
+		}
+		
+		/** @inheritDoc */
+		public function visit(f:Function):void {
+			var k0:int, k:int, u:*, v:Number;
+			for (var i:int=0; i<_r; ++i) {
+				k0 = i*_c;
+				for (var j:int=0; j<_c; ++j) {
+					k = k0 + j;
+					u = _v[k];
+					v = u ? Number(u) : 0;
+					v = f(i,j,v);
+					if (v==0) {
+						delete _v[k];
+					} else {
+						_v[k] = v;
+					}
+				}
+			}
+		}
+
+	} // end of class SparseMatrix
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/DenseMatrix.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/DenseMatrix.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/math/DenseMatrix.as	(revision 15)
@@ -0,0 +1,132 @@
+package gssim.gssimstudio.editor.flare.util.math
+{
+	/**
+	 * A matrix of numbers implemented using an array of values.
+	 */
+	public class DenseMatrix implements IMatrix
+	{
+		private var _r:int;
+		private var _c:int;
+		private var _v:Array;
+		
+		/** The underlying array of values */
+		public function get values():Array { return _v; }
+		/** @inheritDoc */
+		public function get rows():int { return _r; }
+		/** @inheritDoc */
+		public function get cols():int { return _c; }
+		/** @inheritDoc */
+		public function get nnz():int {
+			var nz:int = 0;
+			for (var i:uint=0; i<_v.length; ++i) {
+				if (_v[i] != 0) ++nz;
+			}
+			return nz;
+		}
+		/** @inheritDoc */
+		public function get sum():Number {
+			var sum:Number = 0;
+			for (var i:uint=0; i<_v.length; ++i)
+				sum += _v[i];
+			return sum;
+		}
+		/** @inheritDoc */
+		public function get sumsq():Number {
+			var sumsq:Number = 0;
+			for (var i:uint=0; i<_v.length; ++i)
+				sumsq += _v[i]*_v[i];
+			return sumsq;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new DenseMatrix with the given size. 
+		 * @param rows the number of rows
+		 * @param cols the number of columns
+		 */
+		public function DenseMatrix(rows:int, cols:int) {
+			init(rows, cols);
+		}
+		
+		/** @inheritDoc */
+		public function clone():IMatrix {
+			var m:DenseMatrix = new DenseMatrix(_r, _c);
+			var v:Array = m.values;
+			for (var i:uint=0; i<_v.length; ++i) {
+				v[i] = _v[i];
+			}
+			return m;
+		}
+		
+		/** @inheritDoc */
+		public function like(rows:int, cols:int):IMatrix {
+			return new DenseMatrix(rows, cols);
+		}
+		
+		/** @inheritDoc */
+		public function init(rows:int, cols:int):void {
+			_r = rows;
+			_c = cols;
+			_v = new Array(_r * _c);
+			for (var i:uint=0; i<_v.length; ++i) _v[i]=0;
+		}
+		
+		/** @inheritDoc */
+		public function get(i:int, j:int):Number {
+			return _v[i*_c + j];
+		}
+		
+		/** @inheritDoc */
+		public function set(i:int, j:int, v:Number):Number {
+			_v[i*_c + j] = v;
+			return v;
+		}
+		
+		/** @inheritDoc */
+		public function scale(s:Number):void {
+			for (var i:uint=0; i<_v.length; ++i) _v[i] *= s;
+		}
+		
+		/** @inheritDoc */
+		public function multiply(b:IMatrix):IMatrix {
+			if (cols != b.rows)
+				throw new Error("Incompatible matrix dimensions.");
+			var z:IMatrix = like(rows, b.cols);
+			for (var i:uint=0; i<z.rows; ++i) {
+				for (var j:uint=0; j<z.cols; ++j) {
+					var v:Number = 0;
+					for (var k:uint=0; k<cols; ++k)
+						v += get(i,k) * b.get(k,j);
+					z.set(i, j, v);
+				}
+			}
+			return z;
+		}
+		
+		/** @inheritDoc */
+		public function visitNonZero(f:Function):void {
+			var k0:int, k:int;
+			for (var i:uint=0; i<_r; ++i) {
+				k0 = i*_c;
+				for (var j:uint=0; j<_c; ++j) {
+					k = k0 + j;
+					if (_v[k] != 0) _v[k] = f(i, j, _v[k]);
+				}
+			}
+		}
+		
+		/** @inheritDoc */
+		public function visit(f:Function):void {
+			var k0:int, k:int;
+			for (var i:uint=0; i<_r; ++i) {
+				k0 = i*_c;
+				for (var j:uint=0; j<_c; ++j) {
+					k = k0 + j;
+					_v[k] = f(i, j, _v[k]);
+				}
+			}
+		}
+
+	} // end of class DenseMatrix
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IValueProxy.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IValueProxy.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/IValueProxy.as	(revision 15)
@@ -0,0 +1,33 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	/**
+	 * Interface for classes that get and set named property values of objects.
+	 */
+	public interface IValueProxy
+	{
+		/**
+		 * Gets a named property value for an object. 
+		 * @param object the object
+		 * @param name the property name
+		 * @return the value
+		 */
+		function getValue(object:Object, name:String):*;
+		
+		/**
+		 * Sets a named property value for an object.
+		 * @param object the object
+		 * @param name the property name
+		 * @param value the value
+		 */
+		function setValue(object:Object, name:String, value:*):void;
+		
+		/**
+		 * Returns a value proxy object for getting and setting values. 
+		 * @param object the object
+		 * @return a value proxy object upon which clients can get and set
+		 *  properties directly
+		 */
+		function $(object:Object):Object;
+		
+	} // end of interface IValueProxy
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Sort.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Sort.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/util/Sort.as	(revision 15)
@@ -0,0 +1,206 @@
+package gssim.gssimstudio.editor.flare.util
+{
+	import flash.display.DisplayObjectContainer;
+		
+	/**
+	 * Utility class for sorting and creating sorting functions. This class
+	 * provides a static <code>$()</code> method for creating sorting
+	 * comparison functions from sort criteria. Instances of this class can be
+	 * used to encapsulate a set of sort criteria and retrieve a corresponding
+	 * sorting function.
+	 * 
+	 * <p>Sort criteria are generally expressed as an array of property names
+	 * to sort on. These properties are accessed by sorting functions using the
+	 * <code>Property</code> class. Sort criteria are expressed as an
+	 * array of property names to sort on. These properties are accessed
+	 * by sorting functions using the <code>Property</code> class.
+	 * The default is to sort in ascending order. If the field name
+	 * includes a "-" (negative sign) prefix, that variable will instead
+	 * be sorted in descending order.
+	 * </p>
+	 */
+	public class Sort
+	{
+		/** Prefix indicating an ascending sort order. */
+		public static const ASC:Number = '+'.charCodeAt(0);
+		/** Prefix indicating a descending sort order. */
+		public static const DSC:Number = '-'.charCodeAt(0);
+		
+		private var _comp:Function;
+		private var _crit:Array;
+		
+		/** Gets the sorting comparison function for this Sort instance. */
+		public function get comparator():Function { return _comp; }
+		
+		/** The sorting criteria. Sort criteria are expressed as an
+		 *  array of property names to sort on. These properties are accessed
+		 *  by sorting functions using the <code>Property</code> class.
+		 *  The default is to sort in ascending order. If the field name
+		 *  includes a "-" (negative sign) prefix, that variable will instead
+		 *  be sorted in descending order. */
+		public function get criteria():Array { return Arrays.copy(_crit); }
+		public function set criteria(crit:*):void {
+			if (crit is String) {
+				_crit = [crit];
+			} else if (crit is Array) {
+				_crit = Arrays.copy(crit as Array);
+			} else {
+				throw new ArgumentError("Invalid Sort specification type. " +
+					"Input must be either a String or Array");
+			}
+			_comp = $(_crit);
+		}
+		
+		/**
+		 * Creates a new Sort instance to encapsulate sorting criteria.
+		 * @param crit the sorting criteria. Sort criteria are expressed as an
+		 *  array of property names to sort on. These properties are accessed
+		 *  by sorting functions using the <code>Property</code> class.
+		 *  The default is to sort in ascending order. If the field name
+		 *  includes a "-" (negative sign) prefix, that variable will instead
+		 *  be sorted in descending order.
+		 */
+		public function Sort(crit:*) {
+			this.criteria = crit;
+		}
+		
+		/**
+		 * Sorts the input array according to the sort criteria.
+		 * @param list an array to sort
+		 */
+		public function sort(list:Array):void
+		{
+			mergeSort(list, comparator, 0, list.length-1);
+		}
+		
+		// --------------------------------------------------------------------
+		// Static Methods
+		
+		/**
+		 * Default comparator function that compares two values based on blind
+		 *  application of the less-than and greater-than operators.
+		 * @param a the first value to compare
+		 * @param b the second value to compare
+		 * @return -1 if a < b, 1 if a > b, 0 otherwise.
+		 */
+		public static function defaultComparator(a:*, b:*):int {
+			return a>b ? 1 : a<b ? -1 : 0;
+		}
+		
+		private static function getComparator(cmp:*):Function
+		{
+			var c:Function;
+			if (cmp is Function) {
+				c = cmp as Function;
+			} else if (cmp is Array) {
+				c = $(cmp as Array);
+			} else if (cmp == null) {
+				c = defaultComparator;
+			} else {
+				throw new ArgumentError("Unknown parameter type: "+cmp);	
+			}
+			return c;
+		}
+		
+		/**
+		 * Creates a comparator function using the specification given
+		 * by the input arguments. The resulting sorting function can be used
+		 * to sort objects based on their properties.
+		 * @param a A multi-parameter list or a single array containing a set
+		 * of data field names to sort on, in priority order. The default is
+		 * to sort in ascending order. If the field name includes a "-"
+		 * (negative sign) prefix, that variable will instead be sorted in
+		 * descending order.
+		 * @return a comparison function for use in sorting objects.
+		 */
+		public static function $(...a):Function
+		{
+			if (a && a.length > 0 && a[0] is Array) a = a[0];
+			if (a==null || a.length < 1)
+				throw new ArgumentError("Bad input.");
+
+			if (a.length == 1) {
+				return sortOn(a[0]);
+			} else {
+				var sorts:Array = [];
+				for each (var field:String in a) {
+					sorts.push(sortOn(field));
+				}
+				return multisort(sorts);
+			}
+		}
+		
+		private static function multisort(f:Array):Function
+		{
+			return function(a:Object, b:Object):int {
+				var c:int;
+				for (var i:uint=0; i<f.length; ++i) {
+					if ((c = f[i](a, b)) != 0) return c;
+				}
+				return 0;
+			}
+		}
+		
+		private static function sortOn(field:String):Function
+		{
+			var c:Number = field.charCodeAt(0);
+			var asc:Boolean = (c==ASC || c!=DSC);
+			if (c==ASC || c==DSC) field = field.substring(1);
+			var p:Property = Property.$(field);
+			return function(a:Object, b:Object):int {
+				var da:* = p.getValue(a);
+				var db:* = p.getValue(b);
+				return (asc?1:-1)*(da > db ? 1 : da < db ? -1 : 0);
+			}
+		}
+
+		// --------------------------------------------------------------------
+
+		private static const SORT_THRESHOLD:int = 16;
+
+		private static function insertionSort(a:Array, cmp:Function, p:int, r:int):void
+		{
+			var i:int, j:int, key:Object;
+	        for (j = p+1; j<=r; ++j) {
+	        	key = a[j];
+	            i = j - 1;
+	            while (i >= p && cmp(a[i], key) > 0) {
+	                a[i+1] = a[i];
+	                i--;
+	            }
+	            a[i+1] = key;
+	        }
+    	}
+    	
+    	private static function mergeSort(a:Array, cmp:Function, p:int, r:int):void
+    	{
+	        if (p >= r) {
+	            return;
+	        }
+	        if (r-p+1 < SORT_THRESHOLD) {
+	            insertionSort(a, cmp, p, r);
+	        } else {
+	            var q:int = (p+r)/2;
+	            mergeSort(a, cmp, p, q);
+	            mergeSort(a, cmp, q+1, r);
+	            merge(a, cmp, p, q, r);
+	        }
+    	}
+
+	    private static function merge(a:Array, cmp:Function, p:int, q:int, r:int):void
+	    {
+	    	var t:Array = new Array(r-p+1);
+	    	var i:int, p1:int = p, p2:int = q+1;
+	    	
+	        for (i=0; p1<=q && p2<=r; ++i)
+	        	t[i] = cmp(a[p2], a[p1]) > 0 ? a[p1++] : a[p2++];
+	        for (; p1<=q; ++p1, ++i)
+	            t[i] = a[p1];
+	        for (; p2<=r; ++p2, ++i)
+	            t[i] = a[p2];
+	        for (i=0, p1=p; i<t.length; ++i, ++p1)
+	            a[p1] = t[i];
+	    }
+
+	} // end of class Sort
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Pause.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Pause.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Pause.as	(revision 15)
@@ -0,0 +1,18 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	/**
+	 * Transition representing a pause or dwell in which nothing happens.
+	 * Useful for adding pauses within an animation sequence.
+	 */
+	public class Pause extends Transition
+	{
+		/**
+		 * Creates a new Pause transition with specified duration.
+		 * @param duration the length of the pause, in seconds
+		 */
+		public function Pause(duration:Number) {
+			super(duration);
+		}
+		
+	} // end of class Pause
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/FunctionSequence.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/FunctionSequence.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/FunctionSequence.as	(revision 15)
@@ -0,0 +1,190 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	
+	/**
+	 * Transition that runs sub-transitions in sequential order while also
+	 * invoking a function before each sub-transition is run. Each function
+	 * must take a Transition instance (often a Transitioner) as input.
+	 * Function sequences can only be played forwards; any attempt to play
+	 * one in reverse will result in an error.
+	 * 
+	 * <p>Function sequences are useful for ensuring a particular function
+	 * is run before a sub-transition begins. For example, the function may
+	 * populate the values of a Transitioner on the fly, or may be used to
+	 * control other variables or side-effects that affect the subsequent
+	 * sub-transition(s).</p>
+	 */
+	public class FunctionSequence extends Sequence
+	{
+		/** @private */
+		protected var _funcs:/*Function*/Array = [];
+		/** @private */
+		protected var _offsetStart:Boolean = true;
+		
+		/** Flag indicating if extra time should be added to the transition to
+		 *  offset the running time of invoked functions. True by default. */
+		public function get offsetStartTime():Boolean { return _offsetStart; }
+		public function set offsetStartTime(b:Boolean):void { _offsetStart = b; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new FunctionSequence transition.
+		 */
+		public function FunctionSequence()
+		{
+			super();
+		}
+		
+		/**
+		 * Adds a function call and corresponding transition to this sequence.
+		 * As the sequence plays, functions will be called at the beginning of
+		 * their subsequence, with the provided transition passed as the
+		 * function's sole argument.
+		 * @param f a function to call at the beginning of a sub-sequence
+		 * @param t the transition to run after the function call. This
+		 *  transition will be passed in as an input to the function. This
+		 *  value should be either a <code>Transition</code> instance or
+		 *  a number indicating the duration for a new
+		 *  <code>Transitioner</code>.
+		 */
+		public function push(f:Function, t:*):void
+		{
+			var tr:Transition = t is Transition ? Transition(t)
+			                                    : Transitioner.instance(t);
+			super.add(tr);
+			_funcs.push(f);
+		}
+		
+		/**
+		 * Removes a sub-transition function from this sequence. The
+		 * corresponding transition instance will also be removed.
+		 * @param t the transition to remove
+		 * @return true if the transition was found and removed, false
+		 *  otherwise
+		 */ 
+		public function removeFunction(f:Function):Boolean
+		{
+			if (running) throw new Error("Transition is running!");
+			var idx:int = Arrays.remove(_funcs, f);
+			var rem:Boolean = idx > 0;
+			if (rem) {
+				_trans.splice(idx, 1);
+				_dirty = true;
+			}
+			return rem;
+		}
+		
+		/** @inheritDoc */
+		public override function add(t:Transition):void
+		{
+			super.add(t);
+			_funcs.push(null);
+		}
+		
+		/**
+		 * Removes a sub-transition from this sequence. Any corresponding
+		 * function will also be removed.
+		 * @param t the transition to remove
+		 * @return true if the transition was found and removed, false
+		 *  otherwise
+		 */ 
+		public override function remove(t:Transition):Boolean
+		{
+			if (running) throw new Error("Transition is running!");
+			var idx:int = Arrays.remove(_trans, t);
+			var rem:Boolean = idx > 0;
+			if (rem) {
+				_funcs.splice(idx, 1);
+				_dirty = true;
+			}
+			return rem;
+		}
+		
+		/** @inheritDoc */
+		public override function dispose():void {
+			super.dispose();
+			Arrays.clear(_funcs);
+		}
+	
+		/**
+		 * Plays this function sequence. Function sequences can not be played
+		 * in reverse. 
+		 * @param reverse If true, an error will be thrown and the sequence
+		 *  will not play.
+		 */
+		public override function play(reverse:Boolean=false):void {
+			if (reverse) throw new Error(
+				"Function sequences can't be played in reverse.");
+			super.play(false);
+		}
+		
+		private function invoke(idx:int, t:Transition):void {
+			var f:Function = _funcs[idx];
+			if (f != null) {
+				if (_offsetStart) {
+					var d:Number = new Date().time;
+					f(t);
+					d = new Date().time - d;
+					_start += d;
+				} else {
+					f(t);
+				}
+			}
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Sets up each sub-transition.
+		 */
+		protected override function setup():void
+		{
+		}
+		
+		/**
+		 * Starts this sequence transition, starting the first sub-transition
+		 * to be played.
+		 */
+		protected override function start():void
+		{
+			if (_trans.length > 0) {
+				var t:Transition = _trans[_idx];
+				invoke(_idx, t); t.doSetup(); t.doStart(false);
+			}
+		}
+		
+		/**
+		 * Steps this sequence transition, ensuring that any sub-transitions
+		 * between the previous and current progress fraction are properly
+		 * invoked.
+		 * @param ef the current progress fraction.
+		 */
+		internal override function step(ef:Number):void
+		{
+			// find the right sub-transition
+			var t:Transition, f0:Number, f1:Number, i:int, inc:int;
+			f0 = _fracs[_idx]; f1 = _fracs[_idx+1]; inc = (ef<=f0 ? -1 : 1);
+			
+			for (i = _idx; i>=0 && i<_trans.length; i+=inc) {
+				// get transition and progress fractions
+				t = _trans[i]; f0 = _fracs[i]; f1 = _fracs[i+1];
+				// hand-off to new transition
+				if (i != _idx) {
+					invoke(i, t); t.doSetup(); t.doStart(false);
+				}
+				if ((inc<0 && ef >= f0) || (inc>0 && ef <= f1)) break;
+				t.doStep(inc<0 ? 0 : 1);
+				t.doEnd();
+			}
+			_idx = i; // set the transition index
+			
+			if (_idx >= 0 && _idx < _trans.length) {
+				// run transition with mapped fraction
+				t.doStep(Maths.invLinearInterp(ef, f0, f1));
+			}
+		}
+	} // end of class FunctionSequence
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Scheduler.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Scheduler.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Scheduler.as	(revision 15)
@@ -0,0 +1,182 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	import flash.display.Shape;
+	import flash.events.Event;
+	import flash.events.TimerEvent;
+	import flash.utils.Timer;
+	
+	/**
+	 * Scheduler that oversees animation and time-based processing. Uses an
+	 * internal timer to regularly invoke the current set of scheduled
+	 * objects. Typically, interaction with the scheduler is automatically
+	 * handled by Transition classes. However, custom implmentations of
+	 * the ISchedulable interface will need to be scheduled. Use the
+	 * <tt>Scheduler.instance</tt> property, and not the constructor, to get
+	 * a reference to the active scheduler.
+	 * 
+	 * <p>By default, the Scheduler issues updates to all scheduled items each
+	 * time the Flash Player advances to the next frame, as reported by the
+	 * <code>Event.ENTER_FRAME</code> event. To instead set the update interval
+	 * manually, see the <code>timerInterval</code> property.</p>
+	 */
+	public class Scheduler
+	{
+		private static const _instance:Scheduler = new Scheduler(_Lock);
+		/** The default Scheduler instance. */
+		public static function get instance():Scheduler { return _instance; }
+		
+		private var _scheduled:Array; // list of all currently scheduled items
+		private var _ids:Object;      // map of all named items
+		private var _timer:Timer;     // timer for interval-based scheduling
+		private var _obj:Shape;       // shape for getting ENTER_FRAME events
+		
+		/**
+		 * Sets the timer interval (in milliseconds) at which the scheduler
+		 * should process events. If this value is greater than zero, a
+		 * <code>Timer</code> instance will be used to trigger scheduler
+		 * updates at the given interval. If this value is less than or equal
+		 * to zero (the default), scheduler updates will be issued with each
+		 * time the Flash Player advances to the next frame according to the
+		 * <code>Event.ENTER_FRAME</code> event.
+		 */
+		public function get timerInterval():Number { return _timer.delay; }
+		public function set timerInterval(t:Number):void {
+			pause(); _timer.delay = (t>0 ? t : 0); play();
+		}
+		
+		/**
+		 * Creates a new Scheduler--this constructor should be not used;
+		 * instead use the <code>instance</code> property.
+		 * @param lock a lock object to emulate a private constructor
+		 */
+		public function Scheduler(lock:Class) {
+			if (lock == _Lock) {
+				_scheduled = [];
+				_ids = {};
+				_obj = new Shape();
+				_timer = new Timer(0);
+				_timer.addEventListener(TimerEvent.TIMER, tick);
+			} else {
+				throw new Error("Invalid constructor. Use Scheduler.instance.");
+			}
+		}
+		
+		/**
+		 * Plays the scheduler, allowing it to process events.
+		 */
+		private function play():void
+		{
+			if (timerInterval <= 0) {
+				if (!_obj.hasEventListener(Event.ENTER_FRAME))
+					_obj.addEventListener(Event.ENTER_FRAME, tick);
+			} else if (!_timer.running) {
+				_timer.start();
+			}
+		}
+		
+		/**
+		 * Pauses the scheduler, so that events are not processed.
+		 */
+		private function pause():void
+		{
+			if (timerInterval <= 0) {
+				_obj.removeEventListener(Event.ENTER_FRAME, tick);
+			} else {
+				_timer.stop();
+			}
+		}
+		
+		/**
+		 * Adds an object to the scheduling list.
+		 * @param item a schedulable object to add
+		 */
+		public function add(item:ISchedulable) : void
+		{
+			if (item.id && _ids[item.id] != item) {
+				cancel(item.id);
+				_ids[item.id] = item;
+			}
+			_scheduled.push(item);
+			play();
+		}
+		
+		/**
+		 * Removes an object from the scheduling list.
+		 * @param item the object to remove
+		 * @return true if the object was found and removed, false otherwise
+		 */
+		public function remove(item:ISchedulable) : Boolean
+		{
+			var idx:int = _scheduled.indexOf(item);
+			if (idx >= 0) {
+				_scheduled.splice(idx,1);
+				if (item.id && _ids[item.id] == item) {
+					if (_scheduled.indexOf(item) < 0)
+						delete _ids[item.id];
+				}
+			}
+			return (idx >= 0);
+		}
+		
+		/**
+		 * Indicates if an object with the given id is currently in the
+		 * scheduler queue. 
+		 * @param id the id to check for
+		 * @return true if an object with that id is currently scheduled,
+		 *  false otherwise
+		 */
+		public function isScheduled(id:String) : Boolean
+		{
+			return _ids[id] != undefined;
+		}
+		
+		/**
+		 * Looks up the scheduled object indicated by the given id, if any.
+		 * @param id the id to lookup
+		 * @return the scheduled object with matching id, of null if none
+		 */
+		public function lookup(id:String) : ISchedulable
+		{
+			return id==null ? null : _ids[id];
+		}
+		
+		/**
+		 * Cancels any scheduled object with a matching id. 
+		 * @param id the id to cancel
+		 * @return true if an object was found and cancelled, false otherwise
+		 */
+		public function cancel(id:String) : Boolean
+		{
+			var s:ISchedulable = _ids[id];
+			if (s != null) {
+				remove(s);
+				s.cancelled();
+				return true;
+			} else {
+				return false;
+			}
+		}
+		
+		/**
+		 * Frame/timer callback that invokes each scheduled object.
+		 * @param event the event that triggered the callback
+		 */
+		public function tick(event:Event) : void
+        {
+        	// all events will see the same timestamp
+        	var time:Number = new Date().time;
+        	
+        	for each (var s:ISchedulable in _scheduled) {
+        		if (s.evaluate(time))
+        			remove(s);
+        	}
+        	if (_scheduled.length == 0) {
+        		pause();
+        	}
+        }
+        
+	} // end of class Scheduler
+}
+
+// scheduler lock class to enforce singleton pattern
+class _Lock { }
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Transitioner.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Transitioner.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Transitioner.as	(revision 15)
@@ -0,0 +1,544 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.IValueProxy;
+	
+	import flash.display.DisplayObject;
+	import flash.geom.Rectangle;
+	import flash.utils.Dictionary;
+	
+	/**
+	 * Parallel transition with convenience methods for adding new
+	 * object tweens, helping to incrementally construct a group of transitions.
+	 * A Transitioner will automatically generate tweens for any number of
+	 * items and properties, simplifying the task of creating animated
+	 * transitions. 
+	 * 
+	 * <p>For example, the following code creates a 1 second
+	 * animation for two items. The first item is translated to the point
+	 * (50,50) and the second item is scaled along the x dimension to twice the
+	 * normal size.</p>
+	 * <pre>
+	 * var item1:Sprite, item2:Sprite; // assume these are two drawn sprites
+	 * var t:Transitioner = new Transitioner(1); // create 1-second transition
+	 * t.$(item1).x = 50;
+	 * t.$(item1).y = 50;
+	 * t.$(item2).scaleX = 2;
+	 * t.play();
+	 * </pre>
+	 *
+	 * <p>In the code above, the <code>$</code> method takes an item (this
+	 * can be any ActionScript object, but is often a <code>DisplayObject</code>
+	 * instance) and returns an <code>Object</code> which stores the names of
+	 * the properties to animate and their target values. Behind the scenes,
+	 * the <code>Transitioner</code> automatically creates <code>Tween</code>
+	 * objects as needed.</p>
+	 * 
+	 * <p>The object returned by the <code>$</code> method is a proxy object
+	 * that passes the values to underlying tweens as needed. This same proxy
+	 * object is reused across calls to the <code>$</code> method so do
+	 * <strong>not</strong> attempt to use multiple return values from the
+	 * <code>$</code> method simultaneously. <em>The following example shows
+	 * what you should not do!</em></p>
+	 * <pre>
+	 * var o1:Object = t.$(item1);
+	 * var o2:Object = t.$(item2); // o2==o1, now configured for item2
+	 * o1.x = 5; // actually sets the value 5 to item2, NOT item1
+	 * </pre>
+	 * 
+	 * <p>
+	 * A transitioner can also be set to "immediate" mode, either by setting
+	 * the <code>immediate</code> property to true, or by passing in
+	 * <code>NaN</code> as the duration value to the constructor. When in
+	 * immediate mode, a transitioner will <strong>NOT</strong> generate
+	 * <code>Tween</code> instances to animate the properties. Instead, the
+	 * transitioner will set the values of the target objects immediately.
+	 * For example, when in immediate mode, the <code>$</code> operator is
+	 * equivalent to directly setting the property:
+	 * <code>t.$(item1).x = 50</code> has exactly the same result at
+	 * <code>t.x = 50</code>. The static property
+	 * <code>Transitioner.DEFAULT</code> provides a default instance of an
+	 * immediate-mode transitioner.
+	 * </p>
+	 * 
+	 * <p>
+	 * With these features, transitioners provide a highly flexible way to
+	 * update values in your application. You can write layout and other
+	 * methods once, using a transitioner to update all the property values.
+	 * When animation is desired, a standard transitioner can be passed in
+	 * to your routines. When immediate updates are desired, you can reuse
+	 * the same code, but just pass in a transitioner in immediate mode
+	 * instead. Whether or not value updates are animated or immediate then
+	 * becomes easy to control.
+	 * </p>
+	 * 
+	 * <p>
+	 * Transitioners also provide optimizations to improve animation
+	 * performance. However, they are not enabled by default, as the
+	 * optimizations make some assumptions about how the transitioner will
+	 * be used. See the <code>optimize</code> property and
+	 * <code>dispose</code> method for more information.
+	 * </p>
+	 */
+	public class Transitioner extends Parallel implements IValueProxy
+	{
+		/** The default, immediate-mode transitioner instance. */
+		public static const DEFAULT:Transitioner = new Transitioner(NaN);
+		
+		/**
+		 * Gets a transitioner instance depending upon the input value.
+		 * @param t input determining the transitioner instance to return. If
+		 *  the input is a transitioner, it is simply returned. If the input is
+		 *  a number, a new Transitioner with duration set to the input value
+		 *  is returned, unless the number is less than zero, in which case the
+		 *  default immediate-mode transitioner is returned. If the input is
+		 *  null, <code>Transitioner.DEFAULT</code> is returned.
+		 * @return a Transitioner instance determined by the input
+		 */		
+		public static function instance(t:*):Transitioner {
+			if (t is Number) {
+				var dur:Number = Number(t);
+				return dur<0 ? Transitioner.DEFAULT : new Transitioner(dur);
+			} else if (t == null) {
+				return Transitioner.DEFAULT;
+			} else {
+				return t as Transitioner;
+			}
+		}
+		
+		// --------------------------------------------------------------------
+		
+		private var _immediate:Boolean;
+		private var _lookup:/*Object->Tween*/Dictionary = new Dictionary();
+		
+		private var _proxy:ValueProxy;
+		private var _optimize:Boolean = false;
+		private var _subdur:Number;
+		
+		/** @private */
+		public override function get duration():Number {
+			return _trans.length==0 ? _subdur : super.duration;
+		}
+		
+		/** Immediate mode flag, used to bypass tween generation and perform
+		 *  immediate updates of target object values. */
+		public function get immediate():Boolean { return _immediate; }
+		public function set immediate(b:Boolean):void {
+			_immediate = b;
+			if (!immediate && _proxy == null) _proxy = new ValueProxy(this);
+		}
+		
+		/** 
+		 * Flag indicating if aggressive optimization should be applied.
+		 * This can significantly decrease processing time when large numbers
+		 * of elements are involved. However, the optimization process makes a
+		 * few assumptions about how the transitioner will be used. If these
+		 * assumptions are not met, the animations may exhibit unexpected
+		 * behaviors.
+		 * 
+		 * <p>The assumptions made for optimized transitioners are:
+		 * <ol>
+		 * <li>The property values of tweened objects will not change between
+		 *     the time their target values are set and the transition is
+		 *     played. This allows the transitioner to avoid creating tweens
+		 *     when properties have the same starting and ending values, and
+		 *     immediately set values for DisplayObjects that are not visible.
+		 *     However, this means the starting value must stay the same. In
+		 *     particular, this means that optimized transitioners are often
+		 *     inappropriate for use within a <code>Sequence</code>.</li>
+		 * <li>The transitioner will only be played once, then discarded.
+		 *     This allows the transitioner to automatically recycle all 
+		 *     generated <code>Tween</code> and <code>Interpolator</code>
+		 *     instances, reducing initialization time across transitioners by
+		 *     reusing objects.</li>
+		 * </ol>
+		 * </p>
+		 */
+		public function get optimize():Boolean { return _optimize; }
+		public function set optimize(b:Boolean):void { _optimize = b; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new Transitioner with specified duration.
+		 * @param duration the length of the transition. If this value is NaN,
+		 *  the transitioner will be in immediate mode, in which all changes
+		 *  are immediately applied and no tweens are generated.
+		 * @param easing the easing function to use for this transition. If
+		 *  null, the function Easing.none will be used.
+		 * @param optimize boolean flag indicating if the transitioner should
+		 *  attempt to optimize tween construction. See the documentation
+		 *  for the <code>optimize</code> property for mode details.
+		 * @param id an optional id. If non-null, any other running transition
+		 *  with the same id will be canceled when this transitioner is played.
+		 */
+		public function Transitioner(duration:Number=1, easing:Function=null,
+									 optimize:Boolean=false, id:String=null)
+		{
+			super.easing = easing==null ? DEFAULT_EASING : easing;
+			_subdur = duration;
+			_optimize = optimize;
+			_immediate = isNaN(duration);
+			if (id!=null) this.id = id;
+			if (!_immediate) _proxy = new ValueProxy(this);
+		}
+		
+		/**
+		 * Indicates if the Transitioner contains a Tween for the given object.
+		 * @param o the object to test for
+		 * @return true if there is a Tween for the object, false otherwise
+		 */
+		public function hasTweenFor(o:Object):Boolean
+		{
+			return _immediate ? false : (_lookup[o] != undefined);
+		}
+		
+		/**
+		 * Returns the Tween for the given object, creating a new tween if no
+		 * tween is yet associated with the object. This method returns null if
+		 * the transitioner is in immediate mode.
+		 * @param o the target object
+		 * @return a tween for the input target object, or null if this
+		 *  transitioner is in immediate mode.
+		 */
+		public function _(o:Object):Tween
+		{
+			if (_immediate) return null;
+			
+			var tw:Tween = _lookup[o];
+			if (tw == null) {
+				add(tw = getTween(o, _subdur));
+				tw.easing = Easing.none;
+				_lookup[o] = tw;
+			}
+			return tw;
+		}
+		
+		/**
+		 * Returns the values object of the Tween for the given object. If no
+		 * tween is associated with the object, a new one is created.
+		 * 
+		 * If the transitioner is in immediate mode, then no Tween will be
+		 * created. Instead, the input object will be returned. This allows
+		 * value updates to be set immediately, rather than animated by a
+		 * tween.
+		 * @param o the target object
+		 * @return the <code>values</code> object for the target object's
+		 *  tween, or the target object itself if this transitioner is in
+		 *  immediate mode.
+		 */
+		public function $(o:Object):Object
+		{
+			return _immediate ? o : _proxy.init(o);
+		}
+		
+		/**
+		 * Sets property values for a target object. This method has the same
+		 * effect as setting a property on the object returned by the
+		 * <code>$</code> method.
+		 * 
+		 * <p>If the transitioner is in immediate mode, the property name will
+		 * be parsed and the value set at the end of the property chain. If
+		 * the transitioner is not in immediate mode, the property name and
+		 * values will simply be added to a Tween. If no Tween is associated
+		 * with the input object, a new one will be created.</p>
+		 * 
+		 * @param o the target object
+		 * @param name the property name string
+		 * @param value the property value to set
+		 */
+		public function setValue(o:Object, name:String, value:*):void
+		{
+			if (_immediate) {
+				// set the object property
+				Property.$(name).setValue(o, value);
+			} else if (optimize && getValue(o, name) == value) {
+				// do nothing, optimize the call away...
+			} else if (optimize && o is DisplayObject && !getValue(o, "visible")) {
+				Property.$(name).setValue(o, value);
+			} else {
+				// add to a tween
+				_(o).values[name] = value;
+			}
+		}
+		
+		/**
+		 * Retrieves property values for a target object. This method has the
+		 * same effect as accessing a property using the object returned by the
+		 * <code>$</code> method.
+		 * 
+		 * <p>If the transitioner is in immediate mode, the property name will
+		 * be parsed and the value retrieved diretly from the target object. If
+		 * the transitioner is not in immediate mode, this method will first
+		 * try to lookup the value in the tween <code>values</code> for the
+		 * target object. If this does not succeed, the property value will be
+		 * retrieved directly from the target object itself as in the immediate
+		 * mode case.</p>
+		 * 
+		 * @param o the target object
+		 * @param name the property name string
+		 * @return the property value for the target object, either from the
+		 *  target object's tween values, or, failing that, the object itself.
+		 */
+		public function getValue(o:Object, name:String):*
+		{
+			if (!_immediate) {
+				var tw:Tween = _lookup[o];
+				if (tw != null && tw.values[name] != undefined) {
+					return tw.values[name];
+				}
+			}
+			return Property.$(name).getValue(o);
+		}
+		
+		/**
+		 * Sets the delay of the tween for the given object. If the
+		 * transitioner is in immediate mode, this method has no effect.
+		 * @param o the object to set the delay for
+		 * @param delay the delay, in seconds
+		 */		
+		public function setDelay(o:Object, delay:Number):void
+		{
+			if (!_immediate) {
+				_(o).delay = delay;
+			}
+		}
+				
+		/**
+		 * Gets the delay of the tween for the given object. If the
+		 * transitioner is in immediate mode or no tween has been created for
+		 * the input object, this method returns zero.
+		 * @param o the object to get the delay for
+		 * @return the delay of the tween, or zero if there is no tween
+		 */
+		public function getDelay(o:Object):Number
+		{
+			if (_immediate) return 0;
+			var tw:Tween = _lookup[o];
+			return tw==null ? 0 : tw.delay;
+		}
+		
+		/**
+		 * Sets the removal status of a display object with this transition.
+		 * If true, the display object will be removed from its parent in the
+		 * display list when the transition completes. If this transitioner is
+		 * in immediate mode, any removals are performed immediately.
+		 * @param dobj a display object
+		 * @param b true to remove the display object from the display list
+		 *  at the end of the transition (the default). If false, the removal
+		 *  status will be updated so that the display object will not be
+		 *  removed (not applicable in immediate mode).
+		 */		
+		public function removeChild(dobj:DisplayObject, b:Boolean=true):void
+		{
+			if (_immediate && b) {
+				if (dobj.parent) dobj.parent.removeChild(dobj);
+			} else if (!_immediate) {
+				_(dobj).remove = b;
+			}
+		}
+		
+		/**
+		 * Indicates if a display object is scheduled to be removed from the
+		 * display list when this transition completes. This method always
+		 * returns false if this transitioner is in immediate mode.
+		 * @param d a display object
+		 * @return true if the display object will be removed from the display
+		 *  list at the end of this transition, false otherwise. This method
+		 *  always returns false if the transitioner is in immediate mode.
+		 */
+		public function willRemove(d:DisplayObject):Boolean
+		{
+			if (_immediate) return false;
+			var tw:Tween = _lookup[d];
+			return (tw != null && tw.remove);
+		}
+		
+		/** @inheritDoc */
+		protected override function end():void
+		{
+			super.end();
+			if (_optimize) dispose();
+		}
+		
+		/**
+		 * Disposes of the internal state of this transitioner.
+		 * Contained tweens and their interpolators will be collected and
+		 * recycled for future reuse, improving initialization times for
+		 * subsequent transitioners. This method is automatically called at the
+		 * end of the transition if the <code>optimize</code> flag is true.
+		 * Otherwise, this method can be invoked manually when a transitioner
+		 * is no longer needed.
+		 */
+		public override function dispose():void
+		{
+			while (_trans.length > 0) {
+				var t:Transition = _trans.pop();
+				t.dispose();
+				if (t is Tween) reclaimTween(t as Tween);
+			}
+		}
+		
+		/**
+		 * Computes the approximate size of the given object after this
+		 * transitioner has been run. This calculation is performed by
+		 * applying the final <code>scaleX</code>, <code>scaleY</code>, and
+		 * <code>size</code> values of the object. 
+		 * @param d the display object to compute the size for
+		 * @param r a rectangle for storing the results
+		 * @return a rectangle whose <code>width</code> and <code>height</code>
+		 *  properties contain the end size values. 
+		 */
+		public function endSize(d:DisplayObject, r:Rectangle=null):Rectangle
+		{
+			if (r==null) r = new Rectangle();
+			var t:Tween, v:Object, o:Object = Object(d);
+			var scaleX:Number, scaleY:Number, size:Number;
+			
+			if (_immediate || (t=_lookup[d])==null) {
+				r.width = d.width;
+				r.height = d.height;
+			} else {
+				v = t.values;
+				if (v.hasOwnProperty("scaleX")) {
+					scaleX = d.scaleX;
+					d.scaleX = v.scaleX;
+				}
+				if (v.hasOwnProperty("scaleY")) {
+					scaleY = d.scaleY;
+					d.scaleY = v.scaleY;	
+				}
+				if (v.hasOwnProperty("size")) {
+					size = o.size;
+					o.size = v.size;
+				}
+				r.width = d.width;
+				r.height = d.height;
+				if (v.hasOwnProperty("scaleX")) d.scaleX = scaleX;
+				if (v.hasOwnProperty("scaleY")) d.scaleY = scaleY;
+				if (v.hasOwnProperty("size"))   o.size = size;
+			}
+			return r;
+		}
+		
+		/**
+		 * Computes the approximate bounds of the given object after this
+		 * transitioner has been run. This calculation is performed by
+		 * applying the final <code>scaleX</code>, <code>scaleY</code>,
+		 * <code>size</code>, <code>x</code>, and <code>y</code> values of
+		 * the object. 
+		 * @param d the display object to compute the size for
+		 * @param coords the target coordinate space for the bounds
+		 * @return a rectangle whose <code>width</code> and <code>height</code>
+		 *  properties contain the end size values. 
+		 */
+		public function endBounds(d:DisplayObject,
+			coords:DisplayObject):Rectangle
+		{
+			var r:Rectangle = new Rectangle();
+			var t:Tween, v:Object, o:Object = Object(d);
+			var scaleX:Number, scaleY:Number, size:Number, x:Number, y:Number;
+			
+			if (_immediate || (t=_lookup[d])==null) {
+				r = d.getBounds(coords);
+			} else {
+				v = t.values;
+				if (v.hasOwnProperty("scaleX")) {
+					scaleX = d.scaleX;
+					d.scaleX = v.scaleX;
+				}
+				if (v.hasOwnProperty("scaleY")) {
+					scaleY = d.scaleY;
+					d.scaleY = v.scaleY;	
+				}
+				if (v.hasOwnProperty("size")) {
+					size = o.size;
+					o.size = v.size;
+				}
+				if (v.hasOwnProperty("x")) {
+					x = d.x;
+					d.x = v.x;
+				}
+				if (v.hasOwnProperty("y")) {
+					y = d.y;
+					d.y = v.y;
+				}
+				r = d.getBounds(coords);
+				if (v.hasOwnProperty("scaleX")) d.scaleX = scaleX;
+				if (v.hasOwnProperty("scaleY")) d.scaleY = scaleY;
+				if (v.hasOwnProperty("size"))   o.size = size;
+				if (v.hasOwnProperty("x"))      d.x = x;
+				if (v.hasOwnProperty("y"))      d.y = y;
+			}
+			return r;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		private static var _maxPoolSize:int = 10000;
+		private static var _tweenPool:Array = [];
+		private static var _count:int = 0;
+		
+		private static function getTween(o:Object, duration:Number):Tween
+		{
+			var tw:Tween;
+			if (_tweenPool.length > 0) {
+				tw = _tweenPool.pop();
+				tw.target = o;
+				tw.duration = duration;
+				tw.enabled = true;
+			} else {
+				tw = new Tween(o, duration);
+			}
+			return tw;
+		}
+		
+		private static function reclaimTween(tw:Tween):void
+		{
+			if (_tweenPool.length < _maxPoolSize) {
+				_tweenPool.push(tw);
+			}
+		}
+		
+	} // end of class Transitioner
+}
+
+import gssim.gssimstudio.editor.flare.animate.Transitioner;
+import gssim.gssimstudio.editor.flare.util.Property;
+
+import flash.utils.flash_proxy;
+import flash.utils.Proxy;
+
+/**
+ * Helper class that gets/sets values for a Transitioner.
+ * This layer of indirection allows us to perform "behind-the-scenes"
+ * handling while maintaining simple property assignment syntax.
+ */
+dynamic class ValueProxy extends Proxy
+{
+	private var _trans:Transitioner;
+	private var _object:Object;
+    
+    public function ValueProxy(trans:Transitioner) {
+    	_trans = trans;
+    }
+
+	public function init(obj:Object):Object
+	{
+		_object = obj;
+		return this;
+	}
+
+	override flash_proxy function callProperty(methodName:*, ... args):* {
+		return null;
+	}
+
+    override flash_proxy function getProperty(name:*):* {
+    	return _trans.getValue(_object, name);
+    }
+
+    override flash_proxy function setProperty(name:*, value:*):void {
+        _trans.setValue(_object, name, value);
+    }
+    
+} // end of class ValueProxy
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Tween.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Tween.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Tween.as	(revision 15)
@@ -0,0 +1,175 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	import gssim.gssimstudio.editor.flare.animate.interpolate.Interpolator;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	
+	import flash.display.DisplayObject;
+	
+	/**
+	 * Transition that interpolates (in-be<em>tweens</em>) properties
+	 * of a target object over a time interval. The <tt>values</tt> property
+	 * represents the set of properties to tween and their final values. Any
+	 * arbitrary property (not just visual properties) can be tweened. The
+	 * Tween class handles tweening of Numbers, colors, Dates, Points,
+	 * Rectangles, and numeric Arrays. Properties of other types are simply
+	 * swapped when then Transition half-completes. Tweening for custom types
+	 * is possible, see the <tt>flare.animate.interpolate.Interpolator</tt>
+	 * class for more.
+	 * 
+	 * <p>Starting values are automatically determined from the tweened object.
+	 * Once determined, these starting values are stored to allow both forward
+	 * and backward playback. Use the <tt>reset</tt> method to force a tween to
+	 * redetermine the starting values the next time it is played. Tweens also
+	 * provide a <code>remove</code> flag for DisplayObjects. When set to true,
+	 * a display object will be removed from the display list at the end of the
+	 * tween. Note that playing the tween is reverse will not revert this
+	 * removal.</p>
+	 * 
+	 * <p>Internally, a Tween creates a set of Interpolator objects to compute
+	 * intermediate values for each property included in <tt>values</tt>. Note
+	 * that property names can involve nested properties. For example,
+	 * <tt>{"filters[0].blurX":5}</tt> is a valid tweening property, as both
+	 * array access (<tt>[]</tt>) and property access (<tt>.</tt>) syntax are
+	 * supported.</p>
+	 * 
+	 * <p>To manage a collection of objects being tweened simultaneously, use a
+	 * <tt>Transitioner</tt> object.</p>
+	 */
+	public class Tween extends Transition
+	{
+		// -- Properties ------------------------------------------------------
+		
+		private var _interps:Array = new Array();
+		private var _target:Object;
+		private var _from:Object;
+		private var _remove:Boolean = false;
+		private var _visible:Object = null;
+		private var _values:Object;
+		
+		/** The target object whose properties are tweened. */
+		public function get target():Object { return _target; }
+		public function set target(t:Object):void { _target = t; }
+		
+		/** Flag indicating if the target object should be removed from the
+		 *  display list at the end of the tween. Only applies when the target
+		 *  is a <code>DisplayObject</code>. */
+		public function get remove():Boolean { return _remove; }
+		public function set remove(b:Boolean):void { _remove = b; }
+		
+		/** The properties to tween and their target values. */
+		public function get values():Object { return _values; }
+		public function set values(o:Object):void { _values = o; }
+		
+		/** Optional starting values for tweened properties. */
+		public function get from():Object { return _from; }
+		public function set from(s:Object):void { _from = s; }
+		
+		
+		// - Methods ----------------------------------------------------------
+		
+		/**
+		 * Creates a new Tween with the specified parameters.
+		 * @param target the target object
+		 * @param duration the duration of the tween, in seconds
+		 * @param values the properties to tween and their target values
+		 * @param remove a display list removal flag (for
+		 *  <code>DisplayObject</code> target objects
+		 * @param easing the easing function to use
+		 */
+		public function Tween(target:Object, duration:Number=1,
+			values:Object=null, remove:Boolean=false, easing:Function=null)
+		{
+			super(duration, 0, easing);
+			
+			_target = target;
+			_remove = remove;
+			_values = values==null ? {} : values;
+			_from = {};
+		}
+		
+		/** @inheritDoc */
+		public override function dispose():void
+		{
+			// reclaim any old interpolators
+			while (_interps.length > 0) {
+				Interpolator.reclaim(_interps.pop());
+			}
+			// remove all target values
+			for (var name:String in _values) {
+				delete _values[name];
+			}
+			_visible = null;
+			_remove = false;
+			_target = null;
+		}
+		
+		/**
+		 * Sets up this tween by creating interpolators for each tweened
+		 * property.
+		 */
+		protected override function setup():void
+		{
+			// reclaim any old interpolators
+			while (_interps.length > 0) {
+				Interpolator.reclaim(_interps.pop());
+			}
+			
+			// build interpolators
+			var vc:Object, v0:Object, v1:Object;
+			for (var name:String in _values) {
+				// create interpolator only if start/cur/end values don't match
+				vc = Property.$(name).getValue(_target);
+				v0 = _from.hasOwnProperty(name) ? _from[name] : vc;
+				v1 = _values[name];
+				
+				if (vc != v1 || vc != v0) {
+					if (name == "visible") {
+						// special handling for visibility
+						_visible = Boolean(v1);
+					} else {
+						_interps.push(Interpolator.create(_target, name, v0, v1));
+					}
+				}
+			}
+		}
+		
+		/**
+		 * Updates target object visibility, if appropriate.
+		 */
+		protected override function start():void
+		{
+			// set visibility
+			var item:DisplayObject = _target as DisplayObject;
+			if (item != null && Boolean(_visible))
+				item.visible = true;
+		}
+		
+		/**
+		 * Steps the tween, updating the tweened properties.
+		 */
+		internal override function step(ef:Number):void
+		{
+			// run the interpolators
+			for each (var i:Interpolator in _interps) {
+				i.interpolate(ef);
+			}
+		}
+		
+		/**
+		 * Ends the tween, updating target object visibility and display
+		 * list membership, if appropriate.
+		 */
+		protected override function end():void
+		{
+			// set visibility, remove from display list if requested
+			var item:DisplayObject = _target as DisplayObject;
+			if (item != null) {
+				if (_remove && item.parent != null)
+					item.parent.removeChild(item);
+				if (_visible != null)
+					item.visible = Boolean(_visible);
+			}
+		}
+		
+	} // end of class Tween
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/ISchedulable.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/ISchedulable.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/ISchedulable.as	(revision 15)
@@ -0,0 +1,31 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	/**
+	 * Interface for "schedulable" objects that can be run by
+	 * the Scheduler class.
+	 */
+	public interface ISchedulable
+	{
+		/**
+		 * Evaluate a scheduled call.
+		 * @param time the current time in milliseconds
+		 * @return true if this item should be removed from the scheduler,
+		 * false if it should continue to be run.
+		 */
+		function evaluate(time:Number) : Boolean;
+		
+		/** A unique name identifying this schedulable object. The default
+		 *  is <code>null<code>. If non-null, any other scheduled items with
+		 *  the same id will be canceled upon scheduling.
+		 *  
+		 *  <p>Once an item has been scheduled, it's id should not be changed.
+		 *  However, it is left to subclasses to respect this convention.
+		 *  If it is not followed, erratic cancels may occur.</p> */
+		function get id():String;
+		function set id(n:String):void;
+		
+		/** Invoked if a scheduled item is cancelled by the scheduler. */
+		function cancelled():void;
+		
+	} // end of interface ISchedulable
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/DateInterpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/DateInterpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/DateInterpolator.as	(revision 15)
@@ -0,0 +1,48 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{
+	/**
+	 * Interpolator for <code>Date</code> values.
+	 */
+	public class DateInterpolator extends Interpolator
+	{
+		private var _start:Number;
+		private var _end:Number;
+		private var _d:Date;
+		
+		/**
+		 * Creates a new DateInterpolator.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param start the starting date value to interpolate from
+		 * @param end the target date value to interpolate to
+		 */
+		public function DateInterpolator(target:Object, property:String,
+		                                 start:Object, end:Object)
+		{
+			super(target, property, start, end);
+		}
+		
+		/**
+		 * Initializes this interpolator.
+		 * @param start the starting value of the interpolation
+		 * @param end the target value of the interpolation
+		 */
+		protected override function init(start:Object, end:Object) : void
+		{
+			_d = new Date();
+			_start = (start as Date).time;
+			_end = (end as Date).time - _start;
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public override function interpolate(f:Number) : void
+		{
+			_d.time = _start + f * _end;
+			_prop.setValue(_target, _d);
+		}
+		
+	} // end of class DateInterpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ArrayInterpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ArrayInterpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ArrayInterpolator.as	(revision 15)
@@ -0,0 +1,63 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	
+	/**
+	 * Interpolator for numeric <code>Array</code> values. Each value
+	 * contained in the array should be a numeric (<code>Number</code> or
+	 * <code>int</code>) value.
+	 */
+	public class ArrayInterpolator extends Interpolator
+	{
+		private var _start:Array;
+		private var _end:Array;
+		private var _cur:Array;
+		
+		/**
+		 * Creates a new ArrayInterpolator.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param start the starting array of values to interpolate from
+		 * @param end the target array to interpolate to. This should be an
+		 *  array of numerical values.
+		 */
+		public function ArrayInterpolator(target:Object, property:String,
+		                                  start:Object, end:Object)
+		{
+			super(target, property, start, end);
+		}
+		
+		/**
+		 * Initializes this interpolator.
+		 * @param start the starting value of the interpolation
+		 * @param end the target value of the interpolation
+		 */
+		protected override function init(start:Object, end:Object) : void
+		{
+			_end = end as Array;
+			if (!end) throw new Error("Target array is null!");
+			if (_start && _start.length != _end.length) _start = null;
+			_start = Arrays.copy(start as Array, _start);
+			
+			if (_start.length != _end.length)
+				throw new Error("Array dimensions don't match");
+				
+			var cur:Array = _prop.getValue(_target) as Array;
+			if (cur == end) cur = null;
+			_cur = Arrays.copy(_start, cur);
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public override function interpolate(f:Number) : void
+		{
+			for (var i:uint=0; i<_cur.length; ++i) {
+				_cur[i] = _start[i] + f*(_end[i] - _start[i]);
+			}
+			_prop.setValue(_target, _cur);
+		}
+		
+	} // end of class ArrayInterpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ColorInterpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ColorInterpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ColorInterpolator.as	(revision 15)
@@ -0,0 +1,65 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{	
+	/**
+	 * Interpolator for color (<code>uint</code>) values.
+	 */ 
+	public class ColorInterpolator extends Interpolator
+	{
+		private var _start:uint;
+		private var _end:uint;
+		
+		/**
+		 * Creates a new ColorInterpolator.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param start the starting color value to interpolate from
+		 * @param end the target color value to interpolate to
+		 */
+		public function ColorInterpolator(target:Object, property:String,
+		                                  start:Object, end:Object)
+		{
+			super(target, property, start, end);
+		}
+		
+		/**
+		 * Initializes this interpolator.
+		 * @param start the starting value of the interpolation
+		 * @param end the target value of the interpolation
+		 */
+		protected override function init(start:Object, end:Object) : void
+		{
+			_start = uint(start);
+			_end = uint(end);
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public override function interpolate(f:Number) : void
+		{
+			// we'll do all the work here to avoid the overhead of
+			//  extra method calls (rather than call Colors.interpolate)
+			var a1:uint, a2:uint, r1:uint, r2:uint, 
+			    g1:uint, g2:uint, b1:uint, b2:uint;
+			
+			// get color components
+			a1 = (_start >> 24) & 0xFF; a2 = (_end >> 24) & 0xFF;
+			r1 = (_start >> 16) & 0xFF; r2 = (_end >> 16) & 0xFF;
+			g1 = (_start >>  8) & 0xFF; g2 = (_end >>  8) & 0xFF;
+			b1 =  _start & 0xff;        b2 =  _end & 0xFF;
+			
+			// interpolate the color components
+			a1 += f*(a2-a1); r1 += f*(r2-r1);
+			g1 += f*(g2-g1); b1 += f*(b2-b1);
+			
+			// recombine into final color
+			a1 = ((a1 & 0xFF) << 24) | ((r1 & 0xFF) << 16) |
+				 ((g1 & 0xFF) <<  8) |  (b1 & 0xFF);
+			
+			// update the property value
+			_prop.setValue(_target, a1);
+		}
+		
+	} // end of class ColorInterpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/Interpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/Interpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/Interpolator.as	(revision 15)
@@ -0,0 +1,243 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{
+	import gssim.gssimstudio.editor.flare.util.Property;
+	
+	import flash.utils.getDefinitionByName;
+	import flash.utils.getQualifiedClassName;
+	
+	/**
+	 * Base class for value interpolators. This class also provides factory 
+	 * methods for creating concrete interpolator instances -- see the
+	 * <code>create</code> method for details about interpolator creation.
+	 */
+	public class Interpolator
+	{
+		/** The target object whose property is being interpolated. */
+		protected var _target:Object;
+		/** The property to interpolate. */
+		protected var _prop:Property;
+		
+		/**
+		 * Base constructor for Interpolator instances.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param value the target value of the interpolation
+		 */
+		public function Interpolator(target:Object, property:String,
+									 start:Object, end:Object)
+		{
+			reset(target, property, start, end);
+		}
+		
+		/**
+		 * Re-initializes an exising interpolator instance.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param value the target value of the interpolation
+		 */
+		public function reset(target:Object, property:String,
+		                      start:Object, end:Object):void
+		{
+			_target = target;
+			_prop = Property.$(property);
+			init(start, end);
+		}
+		
+		/**
+		 * Performs initialization of an interpolator, typically by
+		 * initializing the start and ending values. Subclasses should
+		 * override this method for custom initialization.
+		 * @param value the target value of the interpolation
+		 */
+		protected function init(start:Object, end:Object) : void
+		{
+			// for subclasses to override
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value. Subclasses should
+		 * override this method to implement custom interpolation routines.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public function interpolate(f:Number) : void
+		{
+			throw new Error("This is an abstract method");
+		}
+		
+		// -- Interpolator Factory --------------------------------------------
+		
+		private static var _maxPoolSize:int = 10000;
+		private static var _pools:Object = [];
+		private static var _lookup:Object = buildLookupTable();
+		private static var _rules:Array = buildRules();
+		
+		private static function buildLookupTable() : Object
+		{			
+			// add variables to ensure classes are included by compiler
+			var ni:NumberInterpolator;
+			var di:DateInterpolator;
+			var pi:PointInterpolator;
+			var ri:RectangleInterpolator;
+			var mi:MatrixInterpolator;
+			var ai:ArrayInterpolator;
+			var ci:ColorInterpolator;
+			var oi:ObjectInterpolator;
+			
+			// build the value->interpolator lookup table
+			var lut:Object = new Object();
+			lut["Number"] = "flare.animate.interpolate::NumberInterpolator";
+			lut["int"] = "flare.animate.interpolate::NumberInterpolator";
+			lut["Date"] = "flare.animate.interpolate::DateInterpolator";
+			lut["Array"] = "flare.animate.interpolate::ArrayInterpolator";
+			lut["flash.geom::Point"] = "flare.animate.interpolate::PointInterpolator";
+			lut["flash.geom::Rectangle"] = "flare.animate.interpolate::RectangleInterpolator";
+			lut["flash.geom::Matrix"] = "flare.animate.interpolate::MatrixInterpolator";
+			return lut;
+		}
+		
+		private static function buildRules() : Array
+		{
+			var rules:Array = new Array();
+			rules.push(isColor);
+			return rules;
+		}
+		
+		private static function isColor(target:Object, property:String, s:Object, e:Object)
+			: String
+		{
+			return property.indexOf("Color")>=0 || property.indexOf("color")>=0
+				? "flare.animate.interpolate::ColorInterpolator"
+				: null;
+		}
+		
+		/**
+		 * Extends the interpolator factory with a new interpolator type.
+		 * @param valueType the fully qualified class name for the object type
+		 *  to interpolate
+		 * @param interpType the fully qualified class name for the
+		 *  interpolator class type
+		 */
+		public static function addInterpolatorType(valueType:String, interpType:String) : void
+		{
+			_lookup[valueType] = interpType;
+		}
+				
+		/**
+		 * Clears the lookup table of interpolator types, removing all
+		 * type to interpolator mappings.
+		 */
+		public static function clearInterpolatorTypes():void
+		{
+			_lookup = new Object();
+		}
+		
+		/**
+		 * Adds a rule to the interpolator factory. The input function should
+		 * take 4 arguments -- a target object, property name string, a
+		 * starting value, and a target value -- and either return a fully
+		 * qualified class name for the type of interpolator to use, or null if
+		 * this rule does not apply.
+		 * @param f the rule function for supplying custom interpolator types
+		 *  based on contextual conditions
+		 */
+		public static function addInterpolatorRule(f:Function):void
+		{
+			_rules.push(f);
+		}
+		
+		/**
+		 * Clears all interpolator rule functions from the interpolator
+		 * factory.
+		 */
+		public static function clearInterpolatorRules():void
+		{
+			_rules = new Array();
+		}
+		
+		/**
+		 * Returns a new interpolator instance for the given target object,
+		 * property name, and interpolation target value. This factory method
+		 * follows these steps to provide an interpolator instance:
+		 * <ol>
+		 *  <li>The list of installed interpolator rules is consulted, and if a
+		 *      rule returns a non-null class name string, an interpolator of
+		 *      that type will be returned.</li>
+		 *  <li>If all rules return null values, then the class type of the
+		 *      interpolation value is used to look up the appropriate
+		 *      interpolator type for that value. If a matching interpolator
+		 *      type is found, an interpolator is initialized and returned.
+		 *      </li>
+		 *  <li>If no matching type is found, a default ObjectInterpolator
+		 *      instance is initialized and returned.</li>
+		 * </ol>
+		 * 
+		 * <p>By default, the interpolator factory contains two rules. The
+		 * first rule returns the class name of ColorInterpolator for any
+		 * property names containing the string "color" or "Color". The second
+		 * rule returns the class name of ObjectInterpolator for the property
+		 * name "shape".</p>
+		 * 
+		 * <p>The default value type to interpolator type mappings are:
+		 * <ul>
+		 *  <li><code>Number -> NumberInterpolator</code></li>
+		 *  <li><code>int -> NumberInterpolator</code></li>
+		 *  <li><code>Date -> DateInterpolator</code></li>
+		 *  <li><code>Array -> ArrayInterpolator</code></li>
+		 *  <li><code>flash.geom.Point -> PointInterpolator</code></li>
+		 *  <li><code>flash.geom.Rectangle -> RectangleInterpolator</code></li>
+		 * </ul>
+		 * </p>
+		 * 
+		 * <p>The interpolator factory can be extended either by adding new
+		 * interpolation rule functions or by adding new mappings from
+		 * interpolation value types to custom interpolator classes.</p>
+		 */
+		public static function create(target:Object, property:String,
+			                          start:Object, end:Object): Interpolator
+		{
+			// first, check the rules list for an interpolator
+			var name:String = null;
+			for (var i:uint=0; name==null && i<_rules.length; ++i) {
+				name = _rules[i](target, property, start, end);
+			}
+			// if no matching rule, use the type lookup table
+			if (name == null) {
+				name = _lookup[getQualifiedClassName(end)];
+			}
+			// if that fails, use ObjectInterpolator as default
+			if (name == null) {
+				name = "flare.animate.interpolate::ObjectInterpolator";
+			}
+			
+			// now create the interpolator, recycling from the pool if possible
+			var pool:Array = _pools[name] as Array;
+			if (pool == null || pool.length == 0) {
+				// nothing in the pool, create a new instance
+				var Ref:Class = getDefinitionByName(name) as Class;
+				return new Ref(target, property, start, end) as Interpolator;
+			} else {
+				// reuse an interpolator from the object pool
+				var interp:Interpolator = pool.pop() as Interpolator;
+				interp.reset(target, property, start, end);
+				return interp;
+			}
+		}
+		
+		/**
+		 * Reclaims an interpolator for later recycling. The reclaimed
+		 * interpolator should not be in active use by any other classes.
+		 * @param interp the Interpolator to reclaim
+		 */
+		public static function reclaim(interp:Interpolator):void
+		{
+			var type:String = getQualifiedClassName(interp); 
+			var pool:Array = _pools[type] as Array;
+			if (pool == null) {
+				_pools[type] = [interp];
+			} else if (pool.length < _maxPoolSize) {
+				pool.push(interp);
+			}
+		}
+		
+	} // end of class Interpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/MatrixInterpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/MatrixInterpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/MatrixInterpolator.as	(revision 15)
@@ -0,0 +1,71 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{
+	import flash.geom.Matrix;
+	
+	/**
+	 * Interpolator for <code>flash.geom.Matrix</code> values.
+	 */
+	public class MatrixInterpolator extends Interpolator
+	{
+		private var _startA:Number, _startB:Number, _startC:Number;
+		private var _startD:Number, _startX:Number, _startY:Number;
+		private var _rangeA:Number, _rangeB:Number, _rangeC:Number;
+		private var _rangeD:Number, _rangeX:Number, _rangeY:Number;
+		private var _cur:Matrix;
+		
+		/**
+		 * Creates a new MatrixInterpolator.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param start the starting matrix value to interpolate from
+		 * @param end the target matrix value to interpolate to
+		 */
+		public function MatrixInterpolator(target:Object, property:String,
+		                                   start:Object, end:Object)
+		{
+			super(target, property, start, end);
+		}
+		
+		/**
+		 * Initializes this interpolator.
+		 * @param start the starting value of the interpolation
+		 * @param end the target value of the interpolation
+		 */
+		protected override function init(start:Object, end:Object) : void
+		{
+			var e:Matrix = Matrix(end), s:Matrix = Matrix(start);
+			_cur = _prop.getValue(_target) as Matrix;
+			if (_cur == null || _cur == s || _cur == e)
+				_cur = e.clone();
+			
+			_startA = s.a;
+			_startB = s.b;
+			_startC = s.c;
+			_startD = s.d;
+			_startX = s.tx;
+			_startY = s.ty;
+			_rangeA = e.a  - _startA;
+			_rangeB = e.b  - _startB;
+			_rangeC = e.c  - _startC;
+			_rangeD = e.d  - _startD;
+			_rangeX = e.tx - _startX;
+			_rangeY = e.ty - _startY;
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public override function interpolate(f:Number) : void
+		{
+			_cur.a  = _startA + f * _rangeA;
+			_cur.b  = _startB + f * _rangeB;
+			_cur.c  = _startC + f * _rangeC;
+			_cur.d  = _startD + f * _rangeD;
+			_cur.tx = _startX + f * _rangeX;
+			_cur.ty = _startY + f * _rangeY;
+			_prop.setValue(_target, _cur);
+		}
+		
+	} // end of class MatrixInterpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/RectangleInterpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/RectangleInterpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/RectangleInterpolator.as	(revision 15)
@@ -0,0 +1,66 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Interpolator for <code>flash.geom.Rectangle</code> values.
+	 */
+	public class RectangleInterpolator extends Interpolator
+	{
+		private var _startX:Number, _startY:Number;
+		private var _startW:Number, _startH:Number;
+		private var _rangeX:Number, _rangeY:Number;
+		private var _rangeW:Number, _rangeH:Number;
+
+		private var _cur:Rectangle;
+		
+		/**
+		 * Creates a new RectangleInterpolator.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param start the starting rectangle value to interpolate from
+		 * @param end the target re3ctangle value to interpolate to
+		 */
+		public function RectangleInterpolator(target:Object, property:String,
+		                                      start:Object, end:Object)
+		{
+			super(target, property, start, end);
+		}
+		
+		/**
+		 * Initializes this interpolator.
+		 * @param start the starting value of the interpolation
+		 * @param end the target value of the interpolation
+		 */
+		protected override function init(start:Object, end:Object) : void
+		{
+			var e:Rectangle = Rectangle(end), s:Rectangle = Rectangle(start);
+			_cur = _prop.getValue(_target) as Rectangle;
+			if (_cur == null || _cur == s || _cur == e)
+				_cur = e.clone();
+			
+			_startX = s.x;
+			_startY = s.y;
+			_startW = s.width;
+			_startH = s.height;
+			_rangeX = e.x - _startX;
+			_rangeY = e.y - _startY;
+			_rangeW = e.width - _startW;
+			_rangeH = e.height - _startH;
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public override function interpolate(f:Number) : void
+		{
+			_cur.x      = _startX + f * _rangeX;
+			_cur.y      = _startY + f * _rangeY;
+			_cur.width  = _startW + f * _rangeW;
+			_cur.height = _startH + f * _rangeH;
+			_prop.setValue(_target, _cur);
+		}
+		
+	} // end of class RectangleInterpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ObjectInterpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ObjectInterpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/ObjectInterpolator.as	(revision 15)
@@ -0,0 +1,50 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{
+	/**
+	 * Interpolator for arbitrary <code>Object</code> values. Simply swaps the
+	 * initial value for the end value for interpolation fractions greater
+	 * than or equal to 0.5.
+	 */
+	public class ObjectInterpolator extends Interpolator
+	{
+		private var _start:Object;
+		private var _end:Object;
+		
+		/**
+		 * Creates a new ObjectInterpolator.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param start the starting object value to interpolate from
+		 * @param end the target object value to interpolate to
+		 */
+		public function ObjectInterpolator(target:Object, property:String,
+		                                   start:Object, end:Object)
+		{
+			super(target, property, start, end);
+		}
+		
+		/**
+		 * Initializes this interpolator.
+		 * @param start the starting value of the interpolation
+		 * @param end the target value of the interpolation
+		 */
+		protected override function init(start:Object, end:Object) : void
+		{
+			_start = start;
+			_end = end;
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value. This method sets
+		 * the target object's property to the starting value if the
+		 * interpolation fraction is less than 0.5 and to the ending value if
+		 * the fraction is greather than or equal to 0.5.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public override function interpolate(f:Number) : void
+		{
+			_prop.setValue(_target, f < 0.5 ? _start : _end);
+		}
+		
+	} // end of class ObjectInterpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/NumberInterpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/NumberInterpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/NumberInterpolator.as	(revision 15)
@@ -0,0 +1,47 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{
+	/**
+	 * Interpolator for <code>Number</code> and <code>int</code> values.
+	 */
+	public class NumberInterpolator extends Interpolator
+	{
+		private var _start:Number;
+		private var _end:Number;
+		
+		/**
+		 * Creates a new NumberInterpolator.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param start the starting number to interpolate from
+		 * @param end the target number to interpolate to
+		 */
+		public function NumberInterpolator(target:Object, property:String,
+                                           start:Object, end:Object)
+		{
+			super(target, property, start, end);
+		}
+		
+		/**
+		 * Initializes this interpolator.
+		 * @param start the starting value of the interpolation
+		 * @param end the target value of the interpolation
+		 */
+		protected override function init(start:Object, end:Object) : void
+		{
+			_start = Number(start);
+			_end = Number(end);
+			if (isNaN(_start)) _start = _end;
+			_end = _end - _start;
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public override function interpolate(f:Number) : void
+		{
+			_prop.setValue(_target, _start + f*_end);
+		}
+		
+	} // end of class NumberInterpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/PointInterpolator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/PointInterpolator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/interpolate/PointInterpolator.as	(revision 15)
@@ -0,0 +1,57 @@
+package gssim.gssimstudio.editor.flare.animate.interpolate
+{
+	import flash.geom.Point;
+	
+	/**
+	 * Interpolator for <code>flash.geom.Point</code> values.
+	 */
+	public class PointInterpolator extends Interpolator
+	{
+		private var _startX:Number, _startY:Number;
+		private var _rangeX:Number, _rangeY:Number;
+		private var _cur:Point;
+		
+		/**
+		 * Creates a new PointInterpolator.
+		 * @param target the object whose property is being interpolated
+		 * @param property the property to interpolate
+		 * @param start the starting point value to interpolate from
+		 * @param end the target point value to interpolate to
+		 */
+		public function PointInterpolator(target:Object, property:String,
+		                                  start:Object, end:Object)
+		{
+			super(target, property, start, end);
+		}
+		
+		/**
+		 * Initializes this interpolator.
+		 * @param start the starting value of the interpolation
+		 * @param end the target value of the interpolation
+		 */
+		protected override function init(start:Object, end:Object) : void
+		{
+			var e:Point = Point(end), s:Point = Point(start);
+			_cur = _prop.getValue(_target) as Point;
+			if (_cur == null || _cur == s || _cur == e)
+				_cur = e.clone();
+			
+			_startX = s.x;
+			_startY = s.y;
+			_rangeX = e.x - _startX;
+			_rangeY = e.y - _startY;
+		}
+		
+		/**
+		 * Calculate and set an interpolated property value.
+		 * @param f the interpolation fraction (typically between 0 and 1)
+		 */
+		public override function interpolate(f:Number) : void
+		{
+			_cur.x = _startX + f*_rangeX;
+			_cur.y = _startY + f*_rangeY;
+			_prop.setValue(_target, _cur);
+		}
+		
+	} // end of class PointInterpolator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Easing.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Easing.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Easing.as	(revision 15)
@@ -0,0 +1,424 @@
+/*
+Disclaimer for Robert Penner's Easing Equations license:
+
+TERMS OF USE - EASING EQUATIONS
+
+Open source under the BSD License.
+
+Copyright Â© 2001 Robert Penner
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package gssim.gssimstudio.editor.flare.animate
+{
+	/**
+	 * Collection of easing functions to control animation rates.
+	 * The methods of this class are intended to be used either (a) directly as
+	 * values for the <tt>easing</tt> property of <tt>Transition</tt> instances,
+	 * or (b) to generate such easing functions.
+	 * 
+	 * <p>Many of these easing functions are adapted from Robert Penner's
+	 * <a href="http://www.robertpenner.com/">collection of easing functions</a>.
+	 * </p>
+	 */
+	public class Easing
+	{
+		/**
+		 * Constructor, throws an error if called, as this is an abstract class.
+		 */
+		public function Easing() {
+			throw new Error("This is an abstract class.");
+		}
+	
+		// -- Function Generators ---------------------------------------------
+		
+		/**
+		 * Composes any easeIn function with any easeOut function to create a
+		 * custom ease-in/ease-out transition.
+		 * @param fi an ease-in function
+		 * @param fo an ease-out function
+		 * @return the combined ease-in/ease-out function
+		 */		
+		public static function easeInOut(fi:Function, fo:Function):Function {
+			return function(t:Number):Number {
+				if (t < 0.5) return 0.5 * fi(2*t);
+				return 0.5 * (1 + fo(2*t-1));
+			}
+		}
+		
+		/**
+		 * A wrapper that specifies additional arguments to an easing function,
+		 * such that the resulting function can be called with only the time.
+		 * @param f The easing function to wrap
+		 * @param arg A list of arguments. There should only be 1 or 2 arguments.
+		 */
+		public static function delegate(f:Function, ...args):Function {
+			if (args.length == 0 || args.length > 2)
+				throw new ArgumentError("There should only be 1 or 2 extra arguments");
+				
+			return function(t:Number):Number {
+				if (args.length == 1) return f(t,args[0]);
+				return f(t,args[0],args[1]);
+			};
+		}
+		
+		/**
+		 * Easing equation function generator for polynomial easing in: accelerating from zero velocity.
+ 		 *
+ 		 * @param exp   The exponent of the polynomial (2 for quadration, 3 for cubic, etc)
+		 * @return		An ease-in function using the polynomial x^exp
+		 */
+		public static function easeInPoly(exp:Number):Function {
+			return function(t:Number):Number {
+				if (t < 0)  return 0;
+            	if (t > 1)  return 1;
+            	else return Math.pow(t, exp);
+			}
+		}
+
+		/**
+		 * Easing equation function generator for polynomial easing out: decelerating from zero velocity.
+ 		 *
+ 		 * @param exp   The exponent of the polynomial (2 for quadration, 3 for cubic, etc)
+		 * @return		An ease-out function using the polynomial x^exp
+		 */		
+		public static function easeOutPoly(exp:Number):Function {
+			return function(t:Number):Number {
+				if (t < 0)  return 0;
+            	if (t > 1)  return 1;
+            	else return 1 - Math.pow(1-t, exp);
+			}
+		}
+		
+		/**
+		 * Easing equation function generator for polynomial easing in/out: acceleration until halfway, then deceleration.
+ 		 *
+ 		 * @param exp   The exponent of the polynomial (2 for quadration, 3 for cubic, etc)
+		 * @return		An ease-in, ease-out function using the polynomial x^exp
+		 */
+		public static function easeInOutPoly(exp:Number):Function {
+			return function(t:Number):Number {
+				if (t < 0)  return 0;
+            	if (t > 1)  return 1;
+            	if (t < .5) return 0.5 * Math.pow(2*t, exp);
+            	else        return 0.5 * (2 - Math.pow(2*(1-t), exp));
+			}
+		}
+		
+		/**
+		 * Easing equation function generator for polynomial easing out/in: deceleration until halfway, then acceleration.
+ 		 *
+ 		 * @param exp   The exponent of the polynomial (2 for quadration, 3 for cubic, etc)
+		 * @return		An ease-out, ease-in function using the polynomial x^exp
+		 */
+		public static function easeOutInPoly(exp:Number):Function {
+			var fi:Function = easeInPoly(exp);
+			var fo:Function = easeOutPoly(exp);
+			return function(t:Number):Number {
+				if (t < 0.5) return fo(2*t)/2;
+				else return 0.5 * (1 + fi(2*t-1));
+			}
+		}
+	
+	
+		// -- Static Functions ------------------------------------------------
+	
+		/**
+		 * Easing equation that does nothing, simply returns the input value.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function none(t:Number):Number {
+			return t;
+		}
+	
+		/**
+		 * Easing equation function for a sinusoidal (sin(t)) easing in: accelerating from zero velocity.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeInSine (t:Number):Number {
+			return 1 - Math.cos(t * (Math.PI/2));
+		}
+	
+		/**
+		 * Easing equation function for a sinusoidal (sin(t)) easing out: decelerating from zero velocity.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeOutSine (t:Number):Number {
+			return Math.sin(t * (Math.PI/2));
+		}
+	
+		/**
+		 * Easing equation function for a sinusoidal (sin(t)) easing in/out: acceleration until halfway, then deceleration.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeInOutSine (t:Number):Number {
+			return -0.5 * (Math.cos(Math.PI*t) - 1);
+		}
+	
+		/**
+		 * Easing equation function for a sinusoidal (sin(t)) easing out/in: deceleration until halfway, then acceleration.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeOutInSine (t:Number):Number {
+			if (t < 0.5) return easeOutSine (t*2);
+			return easeInSine((t*2)-1);
+		}
+	
+		/**
+		 * Easing equation function for an exponential (2^t) easing in: accelerating from zero velocity.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeInExpo (t:Number):Number {
+			return t==0 ? t : Math.pow(2,10*(t-1)) - 0.001;
+		}
+	
+		/**
+		 * Easing equation function for an exponential (2^t) easing out: decelerating from zero velocity.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeOutExpo (t:Number):Number {
+			return (t==1) ? t : 1.001 * (-Math.pow(2, -10*t) + 1);
+		}
+	
+		/**
+		 * Easing equation function for an exponential (2^t) easing in/out: acceleration until halfway, then deceleration.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeInOutExpo (t:Number):Number {
+			if (t==0 || t==1) return t;
+			if (t < 0.5) return 0.5 * Math.pow(2, 10*(2*t-1)) - 0.0005;
+			return 0.5 * 1.0005 * (-Math.pow(2, -10 * (2*t-1)) + 2);
+		}
+	
+		/**
+		 * Easing equation function for an exponential (2^t) easing out/in: deceleration until halfway, then acceleration.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeOutInExpo (t:Number):Number {
+			if (t < 0.5) return 0.5 * easeOutExpo(2*t);
+			return 0.5 * (1 + easeInExpo(2*t-1));
+		}
+	
+		/**
+		 * Easing equation function for a circular (sqrt(1-t^2)) easing in: accelerating from zero velocity.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeInCirc(t:Number):Number {
+			return -(Math.sqrt(1-t*t) - 1);
+		}
+	
+		/**
+		 * Easing equation function for a circular (sqrt(1-t^2)) easing out: decelerating from zero velocity.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeOutCirc(t:Number):Number {
+			return Math.sqrt(1 - (t=t-1)*t);
+		}
+	
+		/**
+		 * Easing equation function for a circular (sqrt(1-t^2)) easing in/out: acceleration until halfway, then deceleration.
+ 		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeInOutCirc(t:Number):Number {
+			if (t < 0.5) return -0.5 * (Math.sqrt(1 - 4*t*t) - 1);
+			return 0.5 * (Math.sqrt(1 - (t=2*t-2)*t) + 1);
+		}
+	
+		/**
+		 * Easing equation function for a circular (sqrt(1-t^2)) easing out/in: deceleration until halfway, then acceleration.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeOutInCirc(t:Number):Number {
+			if (t < 0.5) return easeOutCirc(2*t);
+			return 0.5 * (1 + easeInCirc(2*t-1));
+		}
+	
+		/**
+		 * Easing equation function for an elastic (exponentially decaying sine wave) easing in: accelerating from zero velocity.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @param a		Amplitude.
+		 * @param p		Period.
+		 * @return		The correct value.
+		 */
+		public static function easeInElastic (t:Number, a:Number = Number.NaN, p:Number = Number.NaN):Number {
+			if (t<=0 || t>=1) return t;  if (!p) p=0.45;
+			var s:Number;
+			if (!a || a < Math.abs(1)) { a=1; s=p/4; }
+			else s = p/(2*Math.PI) * Math.asin (1/a);
+			return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t-s)*(2*Math.PI)/p ));
+		}
+		
+		/**
+		 * Easing equation function for an elastic (exponentially decaying sine wave) easing out: decelerating from zero velocity.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @param a		Amplitude.
+		 * @param p		Period.
+		 * @return		The correct value.
+		 */
+		public static function easeOutElastic (t:Number, a:Number = Number.NaN, p:Number = Number.NaN):Number {
+			return 1 - easeInElastic(1-t, a, p);
+		}
+	
+		/**
+		 * Easing equation function for an elastic (exponentially decaying sine wave) easing in/out: acceleration until halfway, then deceleration.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @param a		Amplitude.
+		 * @param p		Period.
+		 * @return		The correct value.
+		 */
+		public static function easeInOutElastic (t:Number, a:Number = Number.NaN, p:Number = Number.NaN):Number {
+			if (t < 0.5) return 0.5 * easeInElastic(2*t, a, p);
+			return 0.5 * (1 + easeOutElastic(2*t-1, a, p));
+		}
+	
+		/**
+		 * Easing equation function for an elastic (exponentially decaying sine wave) easing out/in: deceleration until halfway, then acceleration.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @param a		Amplitude.
+		 * @param p		Period.
+		 * @return		The correct value.
+		 */
+		public static function easeOutInElastic (t:Number, a:Number = Number.NaN, p:Number = Number.NaN):Number {
+			if (t < 0.5) return 0.5 * easeOutElastic(2*t, a, p);
+			return 0.5 * (1 + easeInElastic(2*t-1, a, p));
+		}
+
+		/**
+		 * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @param s		Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent).
+		 * @return		The correct value.
+		 */
+		public static function easeInBack (t:Number, s:Number = Number.NaN):Number {
+			if (!s) s = 1.70158;
+			return t*t*((s+1)*t - s);
+		}
+	
+		/**
+		 * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out: decelerating from zero velocity.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @param s		Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent).
+		 * @return		The correct value.
+		 */
+		public static function easeOutBack (t:Number, s:Number = Number.NaN):Number {
+			if (!s) s = 1.70158;
+			return 1 - (t=1-t)*t*((s+1)*t - s);
+		}
+	
+		/**
+		 * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @param s		Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent).
+		 * @return		The correct value.
+		 */
+		public static function easeInOutBack (t:Number, s:Number = Number.NaN):Number {
+			if (!s) s = 1.70158 * 1.525;
+			if (t < 0.5) return 0.5 * easeInBack(2*t, s);
+			return 0.5 * (1 + easeOutBack(2*t-1, s));
+		}
+	
+		/**
+		 * Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @param s		Overshoot ammount: higher s means greater overshoot (0 produces cubic easing with no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent).
+		 * @return		The correct value.
+		 */
+		public static function easeOutInBack (t:Number, s:Number = Number.NaN):Number {
+			if (!s) s = 1.70158 * 1.525;
+			if (t < 0.5) return 0.5 * easeOutBack(2*t, s);
+			return 0.5 * (1 + easeInBack(2*t-1, s));
+		}
+	
+		/**
+		 * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in: accelerating from zero velocity.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeInBounce(t:Number):Number {
+			return 1 - easeOutBounce(1-t);
+		}
+	
+		/**
+		 * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out: decelerating from zero velocity.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeOutBounce (t:Number):Number {
+			if (t < (1/2.75)) {
+				return 7.5625*t*t;
+			} else if (t < (2/2.75)) {
+				return (7.5625*(t-=(1.5/2.75))*t + .75);
+			} else if (t < (2.5/2.75)) {
+				return (7.5625*(t-=(2.25/2.75))*t + .9375);
+			} else {
+				return (7.5625*(t-=(2.625/2.75))*t + .984375);
+			}
+		}
+	
+		/**
+		 * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out: acceleration until halfway, then deceleration.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeInOutBounce (t:Number):Number {
+			if (t < 0.5) return 0.5 * easeInBounce(2*t);
+			return 0.5 * (1 + easeOutBounce(2*t-1));
+		}
+	
+		/**
+		 * Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out/in: deceleration until halfway, then acceleration.
+		 *
+		 * @param t		Current time (an animation fraction between 0 and 1).
+		 * @return		The correct value.
+		 */
+		public static function easeOutInBounce (t:Number):Number {
+			if (t < 0.5) return 0.5 * easeOutBounce(2*t);
+			return 0.5 * (1 + easeInBounce(2*t-1));
+		}
+		
+	} // end of class Easing
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Sequence.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Sequence.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Sequence.as	(revision 15)
@@ -0,0 +1,192 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	
+	/**
+	 * Transition that runs multiple transitions one after the other in
+	 * sequence. By default, the total duration of the sequence is the sum of
+	 * the durations and delays of the sub-transitions. If the duration
+	 * of the sequence is set explicitly, the duration and delay for
+	 * sub-transitions will be uniformly scaled to fit within in the new
+	 * time span.
+	 */
+	public class Sequence extends Transition
+	{
+		// -- Properties ------------------------------------------------------
+		
+		/** Array of sequential transitions */
+		protected var _trans:/*Transition*/Array = [];
+		/** @private */
+		protected var _fracs:/*Number*/Array = [];
+		/** @private */
+		protected var _autodur:Boolean = true;
+		/** @private */
+		protected var _dirty:Boolean = false;
+		/** @private */
+		protected var _idx:int = 0;
+		
+		/**
+		 * If true, the duration of this sequence is automatically determined
+		 * by the durations of each sub-transition. This is the default behavior.
+		 */
+		public function get autoDuration():Boolean { return _autodur; }
+		public function set autoDuration(b:Boolean):void {
+			_autodur = b;
+			computeDuration();
+		}
+		
+		/** @inheritDoc */
+		public override function get duration():Number {
+			if (_dirty) computeDuration();
+			return super.duration;
+		}
+		public override function set duration(dur:Number):void {
+			_autodur = false;
+			super.duration = dur;
+			_dirty = true;
+		}
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates a new Sequence transition.
+		 * @param transitions an ordered list of sub-transitions
+		 */
+		public function Sequence(...transitions) {
+			easing = Easing.none;
+			for each (var t:Transition in transitions) {
+				_trans.push(t);
+			}
+			_dirty = true;
+		}
+		
+		/**
+		 * Adds a new transition to the end of this sequence.
+		 * @param t the transition to add
+		 */
+		public function add(t:Transition):void
+		{
+			if (running) throw new Error("Transition is running!");
+			_trans.push(t);
+			_dirty = true;
+		}
+		
+		/**
+		 * Removes a sub-transition from this sequence.
+		 * @param t the transition to remove
+		 * @return true if the transition was found and removed, false
+		 *  otherwise
+		 */ 
+		public function remove(t:Transition):Boolean
+		{
+			if (running) throw new Error("Transition is running!");
+			var rem:Boolean = Arrays.remove(_trans, t) >= 0;
+			if (rem) _dirty = true;
+			return rem;
+		}
+		
+		/**
+		 * Computes the duration of this sequence transition.
+		 */
+		protected function computeDuration():void
+		{
+			var d:Number = 0; _fracs = [0];
+			// collect durations and compute sum
+			for each (var t:Transition in _trans)
+				_fracs.push(d += t.totalDuration);
+			// normalize durations to create progress fractions
+			for (var i:int=1; i<=_trans.length; ++i)
+				_fracs[i] = (d==0 ? 0 : _fracs[i] / d);
+			// set duration and scale
+			if (_autodur) super.duration = d;
+			_dirty = false;
+		}
+		
+		/** @inheritDoc */
+		public override function dispose():void {
+			while (_trans.length > 0) { _trans.pop().dispose(); }
+		}
+		
+		// -- Transition Handlers ---------------------------------------------
+		
+		/** @inheritDoc */
+		public override function play(reverse:Boolean=false):void
+		{
+			if (_dirty) computeDuration();
+			super.play(reverse);
+		}
+		
+		/**
+		 * Sets up each sub-transition.
+		 */
+		protected override function setup():void
+		{
+			// initialize each transition in proper sequence
+			for each (var t:Transition in _trans) {
+				t.doSetup(); t.step(1.0);
+			}
+		}
+		
+		/**
+		 * Starts this sequence transition, starting the first sub-transition
+		 * to be played.
+		 */
+		protected override function start():void
+		{
+			if (_reverse) {
+				// init for reverse playback
+				for (_idx=0; _idx<_trans.length; ++_idx) _trans[_idx].step(1);
+				_idx -= 1;
+			} else {
+				// init for forward playback
+				for (_idx=_trans.length; --_idx>=0;) _trans[_idx].step(0);
+				_idx += 1;
+			}
+			if (_trans.length > 0)
+				_trans[_idx].doStart(_reverse);
+		}
+		
+		/**
+		 * Steps this sequence transition, ensuring that any sub-transitions
+		 * between the previous and current progress fraction are properly
+		 * invoked.
+		 * @param ef the current progress fraction.
+		 */
+		internal override function step(ef:Number):void
+		{
+			// find the right sub-transition
+			var t:Transition, f0:Number, f1:Number, i:int, inc:int;
+			f0 = _fracs[_idx]; f1 = _fracs[_idx+1]; inc = (ef<=f0 ? -1 : 1);
+			
+			for (i = _idx; i>=0 && i<_trans.length; i+=inc) {
+				// get transition and progress fractions
+				t = _trans[i]; f0 = _fracs[i]; f1 = _fracs[i+1];
+				// hand-off to new transition
+				if (i != _idx) t.doStart(_reverse);
+				if ((inc<0 && ef >= f0) || (inc>0 && ef <= f1)) break;
+				t.doStep(inc<0 ? 0 : 1);
+				t.doEnd();
+			}
+			_idx = i; // set the transition index
+			
+			if (_idx >= 0 && _idx < _trans.length) {
+				// run transition with mapped fraction
+				t.doStep(Maths.invLinearInterp(ef, f0, f1));
+			}
+		}
+		
+		/**
+		 * Ends this sequence transition, ending the last transition to be
+		 * played in the sequence as necessary.
+		 */
+		protected override function end():void
+		{
+			if (_idx >= 0 && _idx < _trans.length) {
+				_trans[_idx].doStep(_reverse ? 0 : 1);
+				_trans[_idx].doEnd();
+			}
+		}
+		
+	} // end of class Sequence
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Transition.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Transition.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Transition.as	(revision 15)
@@ -0,0 +1,299 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	
+	import flash.events.EventDispatcher;
+
+	[Event(name="start",  type="flare.animate.TransitionEvent")]
+	[Event(name="step",   type="flare.animate.TransitionEvent")]
+	[Event(name="end",    type="flare.animate.TransitionEvent")]
+	[Event(name="cancel", type="flare.animate.TransitionEvent")]
+
+	/**
+	 * Base class representing an animated transition. Provides support for
+	 * tracking animation progress over a time duration. The Transition class
+	 * also issues events whenever the transition is started, stepped, or
+	 * ended. Register event listeners for <code>TransitionEvents</code> to
+	 * track and respond to a transition's progress.
+	 * 
+	 * <p>Useful subclasses of <code>Transition</code> include the
+	 * <code>Tween</code>, <code>Parallel</code>, <code>Sequence</code>,
+	 * <code>Pause</code>, and <code>Transitioner</code> classes.</p>
+	 */
+	public class Transition extends EventDispatcher implements ISchedulable
+	{
+		/** Default easing function: a cubic slow-in slow-out. */
+		public static var DEFAULT_EASING:Function = Easing.easeInOutPoly(3);
+		
+		/** Constant indicating this Transition needs initialization. */
+		protected static const SETUP:int = 0;
+		/** Constant indicating this Transition has been initialized. */
+		protected static const INIT:int = 1;
+		/** Constant indicating this Transition is currently running. */
+		protected static const RUN:int = 2;
+		
+		// -- Properties ------------------------------------------------------
+
+		private var _easing:Function = DEFAULT_EASING; // easing function
+		
+		private var _id:String = null;        // transition id, default null
+		private var _duration:Number;         // duration, in seconds
+		private var _delay:Number;            // delay, in seconds
+		private var _frac:Number;             // animation fraction
+		private var _state:int = SETUP;       // initialization flag
+		/** @private */
+		protected var _start:Number;          // start time	
+		/** Flag indicating this Transition is currently running. */
+		protected var _running:Boolean = false;
+		/** Flag indicating this Transition is running in reverse. */
+		protected var _reverse:Boolean = false;
+		/** Flag indicating if step events should be processed. */
+		public var enabled:Boolean = true;
+		
+		/** @inheritDoc */
+		public function get id():String { return _id; }
+		public function set id(s:String):void
+		{
+			if (_running) {
+				throw new Error(
+					"The id can't be changed while a transition is running.");
+			} else {
+				_id = s;
+			}
+		}
+		
+		/** The total duration, including both delay and active duration. */
+		public function get totalDuration():Number { return duration + delay; }
+		
+		/** The duration (length) of this Transition, in seconds. */
+		public function get duration():Number { return _duration; }
+		public function set duration(d:Number):void {
+			if (d<0) throw new ArgumentError("Negative duration not allowed.");
+			_duration = d;
+		}
+
+		/** The delay between a call to play and the actual start
+		 *  of the transition, in seconds. */
+		public function get delay():Number { return _delay; }
+		public function set delay(d:Number):void {
+			if (d<0) throw new ArgumentError("Negative delay not allowed.");
+			_delay = d;
+		}
+		
+		/** Fraction between 0 and 1 indicating the current progress
+		 *  of this transition. */
+		public function get progress():Number { return _frac; }
+		internal function set progress(f:Number):void { _frac = f; }
+		
+		/** Easing function used to pace this Transition. */
+		public function get easing():Function { return _easing; }
+		public function set easing(f:Function):void { _easing = f; }
+		
+		/** Indicates if this Transition is currently running. */
+		public function get running():Boolean { return _running; }
+		
+		/** Indicates if this Transition is running in reverse. */
+		public function get reverse():Boolean { return _reverse; }
+		
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates a new Transition.
+		 * @param duration the duration, in seconds
+		 * @param delay the delay, in seconds
+		 * @param easing the easing function
+		 */
+		public function Transition(duration:Number=1, delay:Number=0,
+								   easing:Function=null)
+		{
+			_duration = duration;
+			_delay = delay;
+			_easing = (easing==null ? DEFAULT_EASING : easing);
+		}
+		
+		/**
+		 * Starts running the transition.
+		 * @param reverse if true, the transition is played in reverse,
+		 *  if false (the default), it is played normally.
+		 */
+		public function play(reverse:Boolean = false):void
+		{
+			_reverse = reverse;
+			init();
+			Scheduler.instance.add(this);
+			_running = true;
+		}
+		
+		/**
+		 * Stops the transition and completes it.
+		 * Any end-of-transition actions will still be taken.
+		 * Calling play() after stop() will result in the transition
+		 * starting over from the beginning.
+		 */
+		public function stop():void
+		{
+			Scheduler.instance.remove(this);
+			doEnd(TransitionEvent.END);
+		}
+		
+		/**
+		 * Informs this transition that it was cancelled by the scheduler.
+		 * Assumes that the scheduler has already removed the transition.
+		 * Clients should not call this method, but should use the
+		 * <code>stop()</code> method to end a transition early.
+		 */
+		public function cancelled():void
+		{
+			doEnd(TransitionEvent.CANCEL);
+		}
+		
+		/**
+		 * Resets the transition, so that any cached starting values are
+		 * cleared and reset the next time this transition is played.
+		 */
+		public function reset():void
+		{
+			_state = SETUP;
+		}
+		
+		/**
+		 * Pauses the transition at its current position.
+		 * Calling play() after pause() will resume the transition.
+		 */
+		public function pause():void
+		{
+			Scheduler.instance.remove(this);
+			_running = false;
+		}
+		
+		private function init():void
+		{
+			if (_state == SETUP) doSetup();
+			if (_state == RUN) {
+				var f:Number = _reverse ? (1-_frac) : _frac;
+				_start = new Date().time - f * 1000 * (duration + delay);
+			} else {
+				_start = new Date().time;
+				doStart(_reverse);
+			}
+			_state = RUN;
+		}
+
+		/** @private */
+		internal function doSetup():void
+		{
+			setup();
+			_state = INIT;
+		}
+
+		/** @private */
+		internal function doStart(reverse:Boolean):void
+		{
+			_reverse = reverse;
+			_running = true;
+			_frac = _reverse ? 1 : 0;
+			start();
+			if (hasEventListener(TransitionEvent.START)) {
+				dispatchEvent(new TransitionEvent(TransitionEvent.START, this));
+			}
+		}
+		
+		/** @private */
+		internal function doStep(frac:Number):void
+		{
+			if (!enabled) return;
+			_frac = frac;
+			var f:Number = delay==0 || frac==0 ? frac :
+				Maths.invLinearInterp(frac, delay/totalDuration, 1);
+			if (f >= 0) step(_easing(f));
+			if (hasEventListener(TransitionEvent.STEP)) {
+				dispatchEvent(new TransitionEvent(TransitionEvent.STEP, this));
+			}
+		}
+		
+		/** @private */
+		internal function doEnd(evtType:String):void
+		{
+			_frac = _reverse ? 0 : 1;
+			end();
+			_state = INIT;
+			_running = false;
+			if (hasEventListener(evtType)) {
+				dispatchEvent(new TransitionEvent(evtType, this));
+			}
+		}
+		
+		/**
+		 * Evaluates the Transition, stepping the transition forward.
+		 * @param time the current time in milliseconds
+		 * @return true if this item should be removed from the scheduler,
+		 * false if it should continue to be run.
+		 */
+		public function evaluate(time:Number):Boolean
+		{
+			var t:Number = time - _start;
+			if (t < 0) return false;
+			
+			// step the transition forward
+			var d:Number = 1000 * (duration + delay);
+			t = (d==0 ? 1.0 : t/d);
+			if (t > 1) t = 1; // clamp
+			doStep(_reverse ? 1-t : t);
+			
+			// check if we're done
+			var _done:Boolean = (t >= 1.0);
+			if (_done) { doEnd(TransitionEvent.END); }
+			return _done;
+		}
+		
+		/**
+		 * Disposes of this transition, freeing up any resources held. This
+		 * method is optional, but calling it when a transition is no longer
+		 * needed can help improve overall performance.
+		 */
+		public function dispose():void
+		{
+			// for sub-classes to implement
+		}
+		
+		// -- abstract methods ------------------------------------------------
+		
+		/**
+		 * Transition setup routine. Subclasses should override this function
+		 * to perform custom setup actions.
+		 */
+		protected function setup():void
+		{
+			// for sub-classes to implement
+		}
+		
+		/**
+		 * Transition start routine. Subclasses should override this function
+		 * to perform custom start actions.
+		 */
+		protected function start():void
+		{
+			// for sub-classes to implement
+		}
+		
+		/**
+		 * Transition step routine. Subclasses should override this function
+		 * to perform custom step actions.
+		 */
+		internal function step(ef:Number):void
+		{
+			// for sub-classes to implement
+		}
+		
+		/**
+		 * Transition end routine. Subclasses should override this function
+		 * to perform custom ending actions.
+		 */
+		protected function end():void
+		{
+			// for sub-classes to implement
+		}
+		
+	} // end of class Transition
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Parallel.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Parallel.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/Parallel.as	(revision 15)
@@ -0,0 +1,185 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	
+	/**
+	 * Transition that runs multiple transitions simultaneously (in parallel).
+	 * The duration of this parallel transition is computed as the maximum
+	 * total duration (duration + delay) among the sub-transitions. If the
+	 * duration is explicitly set, the sub-transition lengths will be
+	 * uniformly scaled to fit within the new time span.
+	 */
+	public class Parallel extends Transition
+	{
+		// -- Properties ------------------------------------------------------
+		
+		/** Array of parallel transitions */
+		protected var _trans:/*Transition*/Array = [];
+		/** @private */
+		protected var _equidur:Boolean;
+		/** @private */
+		protected var _dirty:Boolean = false;
+		/** @private */
+		protected var _autodur:Boolean = true;
+
+		/**
+		 * If true, the duration of this sequence is automatically determined
+		 * by the longest sub-transition. This is the default behavior.
+		 */
+		public function get autoDuration():Boolean { return _autodur; }
+		public function set autoDuration(b:Boolean):void {
+			_autodur = b;
+			computeDuration();
+		}
+		
+		/** @inheritDoc */
+		public override function get duration():Number {
+			if (_dirty) computeDuration();
+			return super.duration;
+		}
+		public override function set duration(dur:Number):void {
+			_autodur = false;
+			super.duration = dur;
+			_dirty = true;
+		}
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates a new Parallel transition.
+		 * @param transitions a list of sub-transitions
+		 */
+		public function Parallel(...transitions) {
+			easing = Easing.none;
+			for each (var t:Transition in transitions) {
+				_trans.push(t);
+			}
+			_dirty = true;
+		}
+		
+		/**
+		 * Adds a new sub-transition to this parallel transition.
+		 * @param t the transition to add
+		 */
+		public function add(t:Transition):void {
+			if (running) throw new Error("Transition is running!");
+			_trans.push(t);
+			_dirty = true;
+		}
+		
+		/**
+		 * Removes a sub-transition from this parallel transition.
+		 * @param t the transition to remove
+		 * @return true if the transition was found and removed, false
+		 *  otherwise
+		 */
+		public function remove(t:Transition):Boolean {
+			if (running) throw new Error("Transition is running!");
+			var rem:Boolean = Arrays.remove(_trans, t) >= 0;
+			if (rem) _dirty = true;
+			return rem;
+		}
+		
+		/**
+		 * Staggers the start of each sub-transition by a given interval. This
+		 * method will overwrite the delay settings for each sub-transition.
+		 * @param delay the delay between the start of each sub-transition.
+		 * @param reverse if true, staggering will be applied in the reverse
+		 *  order in which sub-transitions were added.
+		 * @return returns this parallel transition
+		 */
+		public function stagger(delay:Number=0.05, reverse:Boolean=false):Parallel
+		{
+			var d:Number = 0, i:uint = 0;
+			if (reverse) {
+				for (i=_trans.length; --i>=0;) {
+					_trans[i].delay = d;
+					d += delay;
+				}
+			} else {
+				for each (var t:Transition in _trans) {
+					t.delay = d;
+					d += delay;
+				}
+			}
+			_dirty = true;
+			return this;
+		}
+		
+		/**
+		 * Computes the duration of this parallel transition.
+		 */
+		protected function computeDuration():void {
+			var d:Number=0, td:Number;
+			if (_trans.length > 0) d = _trans[0].totalDuration;
+			_equidur = true;	
+			for each (var t:Transition in _trans) {
+				td = t.totalDuration;
+				if (_equidur && td != d) _equidur = false;
+				d = Math.max(d, t.totalDuration);
+			}
+			if (_autodur) super.duration = d;
+			_dirty = false;
+		}
+		
+		/** @inheritDoc */
+		public override function dispose():void {
+			while (_trans.length > 0) { _trans.pop().dispose(); }
+		}
+		
+		// -- Transition Handlers ---------------------------------------------
+
+		/** @inheritDoc */
+		public override function play(reverse:Boolean=false):void
+		{
+			if (_dirty) computeDuration();
+			super.play(reverse);
+		}
+
+		/**
+		 * Sets up each sub-transition.
+		 */
+		protected override function setup():void
+		{
+			for each (var t:Transition in _trans) { t.doSetup(); }
+		}
+		
+		/**
+		 * Starts each sub-transition.
+		 */
+		protected override function start():void
+		{
+			for each (var t:Transition in _trans) { t.doStart(_reverse); }
+		}
+		
+		/**
+		 * Steps each sub-transition.
+		 * @param ef the current progress fraction.
+		 */
+		internal override function step(ef:Number):void
+		{
+			var t:Transition;
+			if (_equidur) {
+				// if all durations are the same, we can skip some calculations
+				for each (t in _trans) { t.doStep(ef); }
+			} else {
+				// otherwise, make sure we respect the different lengths
+				var d:Number = duration;
+				for each (t in _trans) {
+					var td:Number = t.totalDuration;
+					var f:Number = d==0 || td==d ? 1 : td/d;
+					t.doStep(ef>f ? 1 : f==1 ? ef : ef/f);
+				}
+			}
+		}
+		
+		/**
+		 * Ends each sub-transition.
+		 */
+		protected override function end():void
+		{
+			for each (var t:Transition in _trans) { t.doEnd(TransitionEvent.END); }
+		}
+		
+	} // end of class Parallel
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/TransitionEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/TransitionEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/animate/TransitionEvent.as	(revision 15)
@@ -0,0 +1,43 @@
+package gssim.gssimstudio.editor.flare.animate
+{
+	import flash.events.Event;
+
+	/**
+	 * Event fired when a <code>Transition</code>
+	 * starts, steps, ends, or is canceled.
+	 */
+	public class TransitionEvent extends Event
+	{
+		/** A transition start event. */
+		public static const START:String = "start";
+		/** A transition step event. */
+		public static const STEP:String = "step";
+		/** A transition end event. */
+		public static const END:String = "end";
+		/** A transition cancel event. */
+		public static const CANCEL:String = "cancel";
+		
+		private var _t:Transition;
+		
+		/** The transition this event corresponds to. */
+		public function get transition():Transition { return _t; }
+		
+		/**
+		 * Creates a new TransitionEvent.
+		 * @param type the event type (START, STEP, or END)
+		 * @param t the transition this event corresponds to
+		 */		
+		public function TransitionEvent(type:String, t:Transition)
+		{
+			super(type);
+			_t = t;
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Event
+		{
+			return new TransitionEvent(type, _t);
+		}
+		
+	} // end of class TransitionEvent
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/flex/FlareVis.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/flex/FlareVis.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/flex/FlareVis.as	(revision 15)
@@ -0,0 +1,129 @@
+package gssim.gssimstudio.editor.flare.flex
+{
+	import gssim.gssimstudio.editor.flare.data.DataSet;
+	import gssim.gssimstudio.editor.flare.display.DirtySprite;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.axis.Axes;
+	import gssim.gssimstudio.editor.flare.vis.axis.CartesianAxes;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	
+	import mx.containers.Canvas;
+
+	/**
+	 * Flex component that wraps a Flare visualization instance. This class can
+	 * be used to create Flare visualizations within an MXML file. The
+	 * underlying Flare <code>Visualization</code> instance can always be
+	 * accessed using the <code>visualization</code> property.
+	 */
+	public class FlareVis extends Canvas
+	{
+		private var _vis:Visualization;
+		
+		/** The visualization operators used by this visualization. This
+		 *  should be an array of IOperator instances. */
+		public function set operators(a:Array):void {
+			_vis.operators.list = a;
+			_vis.update();
+		}
+		
+		/** The interactive controls used by this visualization. This
+		 *  should be an array of IControl instances. */
+		public function set controls(a:Array):void {
+			_vis.controls.list = a;
+			_vis.update();
+		}
+		
+		/** Sets the data visualized by this instance. The input value can be
+		 *  an array of data objects, a Data instance, or a DataSet instance.
+		 *  Any existing data will be removed and new NodeSprite instances will
+		 *  be created for each object in the input arrary. */
+		public function set dataSet(d:*):void {
+			var dd:Data;
+			
+			if (d is Data) {
+				dd = Data(d);
+			} else if (d is Array) {
+				dd = Data.fromArray(d as Array);
+			} else if (d is DataSet) {
+				dd = Data.fromDataSet(d as DataSet);
+			} else {
+				throw new Error("Unrecognized data set type: "+d);
+			}
+			_vis.data = dd;
+			_vis.operators.setup();
+			_vis.update();
+		}
+		
+		/** Returns the axes for the backing visualization instance. */
+		public function get axes():Axes { return _vis.axes; }
+		
+		/** Returns the CartesianAxes for the backing visualization instance. */
+		public function get xyAxes():CartesianAxes { return _vis.xyAxes; }
+		
+		/** Returns the backing Flare visualization instance. */
+		public function get visualization():Visualization {
+			return _vis;
+		}
+		public function set visualization(v:Visualization):void{
+			if (rawChildren.contains(_vis))
+				rawChildren.removeChild(_vis);
+			_vis = v;
+			rawChildren.addChild(_vis);
+			_vis.x = _margin;
+		}
+		
+		public function get visWidth():Number { return _vis.bounds.width; }
+		public function set visWidth(w:Number):void {
+			_vis.bounds.width = w;
+			_vis.update();
+			invalidateSize();
+		}
+		
+		public function get visHeight():Number { return _vis.bounds.height; }
+		public function set visHeight(h:Number):void {
+			_vis.bounds.height = h;
+			_vis.update();
+			invalidateSize();
+		}
+		
+		// --------------------------------------------------------------------
+		
+		private var _margin:int = 10;
+		
+		/**
+		 * Creates a new FlareVis component. By default, a new visualization
+		 * with an empty data set is created.
+		 * @param data the data to visualize. If this value is null, a new
+		 *  empty data instance will be used.
+		 */
+		public function FlareVis(data:Data=null) {
+			this.rawChildren.addChild(
+				_vis = new Visualization(data==null ? new Data() : data)
+			);
+			_vis.x = _margin;
+		}
+		
+		// -- Flex Overrides --------------------------------------------------
+		
+		/** @private */
+		public override function getExplicitOrMeasuredWidth():Number {
+			DirtySprite.renderDirty(); // make sure everything is current
+			var w:Number = _vis.bounds.width;
+			if (_vis.width > w) {
+				// TODO: this is a temporary hack. fix later!
+				_vis.x = _margin + Math.abs(_vis.getBounds(_vis).x);
+				w = _vis.width;
+			}
+			return 2*_margin + Math.max(super.getExplicitOrMeasuredWidth(), w);
+		}
+		
+		/** @private */
+		public override function getExplicitOrMeasuredHeight():Number {
+			DirtySprite.renderDirty(); // make sure everything is current
+			return Math.max(super.getExplicitOrMeasuredHeight(),
+							_vis.bounds.height,
+							_vis.height);
+		}
+		
+	} // end of class FlareVis
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/Visualization.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/Visualization.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/Visualization.as	(revision 15)
@@ -0,0 +1,457 @@
+package gssim.gssimstudio.editor.flare.vis
+{
+	import gssim.gssimstudio.editor.flare.animate.ISchedulable;
+	import gssim.gssimstudio.editor.flare.animate.Scheduler;
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Displays;
+	import gssim.gssimstudio.editor.flare.vis.axis.Axes;
+	import gssim.gssimstudio.editor.flare.vis.axis.CartesianAxes;
+	import gssim.gssimstudio.editor.flare.vis.controls.ControlList;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.Tree;
+	import gssim.gssimstudio.editor.flare.vis.events.DataEvent;
+	import gssim.gssimstudio.editor.flare.vis.events.VisualizationEvent;
+	import gssim.gssimstudio.editor.flare.vis.operator.IOperator;
+	import gssim.gssimstudio.editor.flare.vis.operator.OperatorList;
+	
+	import flash.display.DisplayObject;
+	import flash.display.Sprite;
+	import flash.events.Event;
+	import flash.geom.Rectangle;
+
+	[Event(name="update", type="flare.vis.events.VisualizationEvent")]
+
+	/**
+	 * The Visualization class represents an interactive data visualization.
+	 * A visualization instance consists of
+	 * <ul>
+	 *  <li>A <code>Data</code> instance containing <code>DataSprite</code>
+	 *      objects that visually represent individual data elements</li>
+	 *  <li>An <code>OperatorList</code> of visualization operators that
+	 *      determine visual encodings for position, color, size and other
+	 *      properties.</li>
+	 *  <li>A <code>ControlList</code> of interactive controls that enable
+	 *      interaction with the visualized data.</li>
+	 *  <li>An <code>Axes</code> instance for presenting axes for metric
+	 *      data visualizations. Axes are often configuring automatically by
+	 *      the visualization's operators.</li>
+	 * </ul>
+	 * 
+	 * <p>Visual objects are added to the display list within the
+	 * <code>marks</code> property of the visualization, as the
+	 * <code>Data</code> object is not a <code>DisplayObjectContainer</code>.
+	 * </p>
+	 * 
+	 * <p>All visual elements are contained within <code>layers</code> Sprite.
+	 * This includes the <code>axes</code>, <code>marks</code>, and
+	 * (optionally) <code>labels</code> layers. Clients who wish to add
+	 * additional layers to a visualization should add them directly to the
+	 * <code>layers</code> sprite. Just take care to maintain the desired order
+	 * of elements to avoid occlusion.</p>
+	 * 
+	 * <p>To create a new Visualization, load in a data set, construct
+	 * a <code>Data</code> instance, and instantiate a new
+	 * <code>Visualization</code> with the input data. Then add the series
+	 * of desired operators to the <code>operators</code> property to 
+	 * define the visual encodings.</p>
+	 * 
+	 * @see flare.vis.operator
+	 */
+	public class Visualization extends Sprite
+	{	
+		// -- Properties ------------------------------------------------------
+		
+		private var _bounds:Rectangle = new Rectangle(0,0,500,500);
+		
+		private var _layers:Sprite; // sprite for all layers in visualization
+		private var _marks:Sprite;  // sprite for all visualized data items
+		private var _labels:Sprite; // (optional) sprite for labels
+		private var _axes:Axes;     // (optional) axes, lines, and axis labels
+		
+		private var _data:Data;     // data structure holding visualized data
+		
+		private var _ops:Object;              // map of all named operators
+		private var _operators:OperatorList;  // the "main" operator list
+		private var _controls:ControlList;    // interactive controls
+		private var _rec:ISchedulable; // for running continuous updates
+		
+		/** An object storing extra properties for the visualziation. */
+		public var props:Object = {};
+		
+		/** The layout bounds of the visualization. This determines the layout
+		 *  region for data elements. For example, with an axis layout, the
+		 *  bounds determined the data layout region--this does not include
+		 *  space used by axis labels. */
+		public function get bounds():Rectangle { return _bounds; }
+		public function set bounds(r:Rectangle):void {
+			_bounds = r;
+			if (stage) stage.invalidate();
+		}
+		
+		/** Container sprite holding each layer in the visualization. */
+		public function get layers():Sprite { return _layers; }
+		
+		/** Sprite containing the <code>DataSprite</code> instances. */
+		public function get marks():Sprite { return _marks; }
+		
+		/** Sprite containing a separate layer for labels. Null by default. */
+		public function get labels():Sprite { return _labels; }
+		public function set labels(l:Sprite):void {
+			if (_labels != null)
+				_layers.removeChild(_labels);
+			_labels = l;
+			if (_labels != null) {
+				_labels.name = "_labels";
+				_layers.addChildAt(_labels, _layers.getChildIndex(_marks)+1);
+			}
+		}
+		
+		/**
+		 * The axes for this visualization. May be null if no axes are needed.
+		 */
+		public function get axes():Axes { return _axes; }
+		public function set axes(a:Axes):void {
+			if (_axes != null)
+				_layers.removeChild(_axes);
+			_axes = a;
+			if (_axes != null) {
+				_axes.visualization = this;
+				_axes.name = "_axes";
+				_layers.addChildAt(_axes, 0);
+			}
+		}
+		/** The axes as an x-y <code>CartesianAxes</code> instance. Returns
+		 *  null if <code>axes</code> is null or not a cartesian axes instance.
+		 */
+		public function get xyAxes():CartesianAxes { return _axes as CartesianAxes; }
+		
+		/** The visual data elements in this visualization. */
+		public function get data():Data { return _data; }
+		
+		/** Tree structure of visual data elements in this visualization.
+		 *  Generates a spanning tree over a graph structure, if necessary. */
+		public function get tree():Tree { return _data.tree; }
+		public function set data(d:Data):void
+		{
+			if (_data != null) {
+				_data.visit(_marks.removeChild);
+				_data.removeEventListener(DataEvent.ADD, dataAdded);
+				_data.removeEventListener(DataEvent.REMOVE, dataRemoved);
+			}
+			_data = d;
+			if (_data != null) {
+				_data.visit(_marks.addChild);
+				_data.addEventListener(DataEvent.ADD, dataAdded);
+				_data.addEventListener(DataEvent.REMOVE, dataRemoved);
+			}
+		}
+
+		/** The operator list for defining the visual encodings. */
+		public function get operators():OperatorList { return _operators; }
+		
+		/** The control list containing interactive controls. */
+		public function get controls():ControlList { return _controls; }
+		
+		/** Flag indicating if the visualization should update with every
+		 *  frame. False by default. */
+		public function get continuousUpdates():Boolean { return _rec != null; }
+		public function set continuousUpdates(b:Boolean):void
+		{
+			if (b && _rec==null) {
+				_rec = new Recurrence(this);
+				Scheduler.instance.add(_rec);
+			}
+			else if (!b && _rec!=null) {
+				Scheduler.instance.remove(_rec);
+				_rec = null;
+			}
+		}
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates a new Visualization with the given data and axes.
+		 * @param data the <code>Data</code> instance containing the
+		 *  <code>DataSprite</code> elements in this visualization.
+		 * @param axes the <code>Axes</code> to use with this visualization.
+		 *  Null by default; layout operators may re-configure the axes.
+		 */
+		public function Visualization(data:Data=null, axes:Axes=null) {
+			addChild(_layers = new Sprite());
+			_layers.name = "_layers";
+			
+			_layers.addChild(_marks = new Sprite()); 
+			_marks.name = "_marks";
+			
+			if (data != null) this.data = data;
+			if (axes != null) this.axes = axes;
+			
+			_operators = new OperatorList();
+			_operators.visualization = this;
+			_ops = { main:_operators };
+			
+			_controls = new ControlList();
+			_controls.visualization = this;
+			
+			Displays.addStageListener(this, Event.RENDER,
+				setHitArea, false, int.MIN_VALUE+1);
+		}
+		
+		/**
+		 * Update this visualization, re-calculating axis layout and running
+		 * the operator chain. The input transitioner is used to actually
+		 * perform value updates, enabling animated transitions. This method
+		 * also issues a <code>VisualizationEvent.UPDATE</code> event to any
+		 * registered listeners.
+		 * @param t a transitioner or time span for updating object values. If
+		 *  the input is a transitioner, it will be used to store the updated
+		 *  values. If the input is a number, a new Transitioner with duration
+		 *  set to the input value will be used. The input is null by default,
+		 *  in which case object values are updated immediately.
+		 * @param operators an optional list of named operators to run in the
+		 *  update. 
+		 * @return the transitioner used to store updated values.
+		 */
+		public function update(t:*=null, ...operators):Transitioner
+		{
+			if (operators) {
+				if (operators.length == 0) {
+					operators = null;
+				} else if (operators[0] is Array) {
+					operators = operators[0].length > 0 ? operators[0] : null;
+				}
+			}
+			var trans:Transitioner = Transitioner.instance(t);
+			if (_axes != null) _axes.update(trans);
+			if (operators) {
+				for each (var name:String in operators) {
+					if (_ops.hasOwnProperty(name))
+						_ops[name].operate(trans);
+					else
+						throw new Error("Unknown operator: " + name);
+				}
+			} else {
+				_operators.operate(trans);
+			}
+			if (_axes != null) _axes.update(trans);
+			fireEvent(VisualizationEvent.UPDATE, trans, operators);
+			return trans;
+		}
+		
+		/**
+		 * A function generator that can be used to invoke a visualization
+		 * update at a later time. This method returns a function that
+		 * accepts a <code>Transitioner</code> as its sole argument and then
+		 * executes a visualization update using the specified named
+		 * operators. 
+		 * @param operators an optional array of named operators to run
+		 * @return a function that takes a <code>Transitioner</code> argument
+		 *  and invokes an update.
+		 */
+		public function updateLater(...operators):Function
+		{
+			return function(t:Transitioner):Transitioner {
+				return update(t, operators);
+			}
+		}
+		
+		/**
+		 * Updates the data display bounds for a visualization based on a
+		 * given aspect ratio and provided width and height values. If both
+		 * width and height values are provided, they will be treated as the
+		 * maximum bounds. If only one of the width or height is provided, then
+		 * the width or height will match that value, and the other will be
+		 * determined by the aspect ratio. Finally, if neither width nor height
+		 * is provided, then the current width and height of the display bounds
+		 * will be used as the maximum bounds. After calling this method, a
+		 * call to <code>update</code> is necessary to reflect the change.
+		 * @param ar the desired aspect ratio for the data display
+		 * @param width the desired width. If a height value is also provided,
+		 *  this width value will be treated as the maximum possible width
+		 *  (the actual width may be lower).
+		 * @param height the desired height. If a width value is also provided,
+		 *  this height value will be treated as the maximum possible height
+		 *  (the actual height may be lower).
+		 */
+		public function setAspectRatio(ar:Number, width:Number=-1,
+			height:Number=-1):void
+		{
+			// compute new bounds
+			if (width > 0 && height < 0) {
+				height = width / ar;
+			} else if (width < 0 && height > 0) {
+				width = ar * height;
+			} else {
+				if (width < 0 && height < 0) {
+					width = bounds.width;
+					height = bounds.height;
+				}
+				if (ar > 1) {          // width > height
+					height = width / ar;
+				} else if (ar < 1) {   // height > width
+					width = ar * height;
+				}
+			}	
+			// update bounds
+			bounds.width = width;
+			bounds.height = height;
+		}
+		
+		// -- Named Operators -------------------------------------------------
+		
+		/**
+		 * Sets a new named operator. This method can be used to add extra
+		 * operators to a visualization, in addition to those in the main
+		 * <code>operators</code> property. These operators can be invoked by
+		 * passing the operator name as an additional parameter of the
+		 * <code>update</code> method. If an operator of the same name
+		 * already exists, it will be replaced. Note that the name "main"
+		 * refers to the same operator list as the <code>operators</code>
+		 * property and can not be replaced. 
+		 * @param name the name of the operator to add
+		 * @param op the operator to add
+		 * @return the added operator
+		 */
+		public function setOperator(name:String, op:IOperator):IOperator
+		{
+			if (name=="main") {
+				throw new ArgumentError("Illegal group name: " + 
+						"\"main\" is a reserved name.");
+			}
+			_ops[name] = op;
+			op.visualization = this;
+			return op;
+		}
+		
+		/**
+		 * Removes a named operator. An error will be thrown if the caller
+		 * attempts to remove the operator "main". 
+		 * @param name the name of the operator to remove
+		 * @return the removed operator
+		 */
+		public function removeOperator(name:String):IOperator
+		{
+			if (name=="main") {
+				throw new ArgumentError("Illegal group name: " + 
+						"\"main\" is a reserved name.");
+			}
+			var op:IOperator = _ops[name];
+			if (op) delete _ops[name];
+			return op;
+		}
+		
+		/**
+		 * Retrieves the operator with the given name.  The name "main" will
+		 * return the operator list stored in the <code>operators</code>
+		 * property.
+		 * @param name the name of the operator
+		 * @return the operator
+		 */
+		public function operator(name:String):IOperator
+		{
+			return _ops[name];
+		}
+
+		// -- Event Handling --------------------------------------------------
+
+		/**
+		 * Creates a sprite covering the bounds for this visualization and
+		 * sets it to be this visualization's hit area. Typically, this
+		 * method is triggered in response to a <code>RENDER</code> event.
+		 * <p>To disable automatic hit area calculation, use
+		 * <code>stage.removeEventListener(Event.RENDER, vis.setHitArea)</code>
+		 * <em>after</em> the visualization has been added to the stage.</p>
+		 * @param evt an event that triggered the hit area update
+		 */
+		public function setHitArea(evt:Event=null):void
+		{
+			// get the union of the specified and actual bounds
+			var rb:Rectangle = getBounds(this);
+			var x1:Number = rb.left, x2:Number = rb.right;
+			var y1:Number = rb.top, y2:Number = rb.bottom;
+			if (bounds) {
+				x1 = Math.min(x1, bounds.left);
+				y1 = Math.min(y1, bounds.top);
+				x2 = Math.max(x2, bounds.right);
+				y2 = Math.max(y1, bounds.bottom);
+			}
+			
+			// create the hit area sprite
+			var hit:Sprite = getChildByName("_hitArea") as Sprite;
+			if (hit == null) {
+				hit = new Sprite();
+				hit.name = "_hitArea";
+				addChildAt(hit, 0);
+			}
+			hit.visible = false;
+			hit.mouseEnabled = false;
+			hit.graphics.clear();
+			hit.graphics.beginFill(0xffffff, 1);
+			hit.graphics.drawRect(x1, y1, x2-x1, y2-y1);
+			hitArea = hit;
+		}
+
+		/**
+		 * Fires a visualization event of the given type.
+		 * @param type the type of the event
+		 * @param t a transitioner that listeners should use for any value
+		 *  updates performed in response to this event
+		 */
+		protected function fireEvent(type:String, t:Transitioner,
+			params:Array):void
+		{			
+			// fire event, if anyone is listening
+			if (hasEventListener(type)) {
+				dispatchEvent(new VisualizationEvent(type, t, params));
+			}
+		}
+		
+		/**
+		 * Data listener invoked when new items are added to this
+		 * Visualization's <code>data</code> instance.
+		 * @param evt the data event
+		 */
+		protected function dataAdded(evt:DataEvent):void
+		{
+			if (evt.node) {
+				for each (var d:DisplayObject in evt.items)
+					_marks.addChild(d);
+			} else {
+				for each (d in evt.items)
+					_marks.addChildAt(d, 0);
+			}
+		}
+		
+		/**
+		 * Data listener invoked when new items are removed from this
+		 * Visualization's <code>data</code> instance.
+		 * @param evt the data event
+		 */
+		protected function dataRemoved(evt:DataEvent):void
+		{
+			for each (var d:DisplayObject in evt.items)
+				_marks.removeChild(d);
+		}
+
+	} // end of class Visualization
+}
+
+import gssim.gssimstudio.editor.flare.animate.ISchedulable;
+import gssim.gssimstudio.editor.flare.vis.Visualization;
+
+/**
+ * Simple ISchedulable instance that repeatedly calls a Visualization's
+ * <code>update</code> method.
+ */
+class Recurrence implements ISchedulable {
+	private var _vis:Visualization;
+	public function get id():String { return null; }
+	public function set id(s:String):void { /* do nothing */ }
+	public function cancelled():void { /* do nothing */ }
+	public function Recurrence(vis:Visualization) {
+		_vis = vis;
+	}
+	public function evaluate(t:Number):Boolean {
+		_vis.update(); return false;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/HoverControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/HoverControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/HoverControl.as	(revision 15)
@@ -0,0 +1,136 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.vis.events.SelectionEvent;
+	
+	import flash.display.DisplayObject;
+	import flash.display.DisplayObjectContainer;
+	import flash.display.InteractiveObject;
+	import flash.events.MouseEvent;
+
+	[Event(name="add",    type="flare.vis.events.SelectionEvent")]
+	[Event(name="remove", type="flare.vis.events.SelectionEvent")]
+
+	/**
+	 * Interactive control for responding to mouse hover events. Select and
+	 * deselect event listeners can be added to respond to mouse roll over
+	 * and roll out, respectively.
+	 * 
+	 * <p>This control also provides multiple policies on how the drawing order
+	 * of items may be affected by a hover event. By default no changes are made
+	 * (<code>DONT_MOVE</code>). The <code>MOVE_TO_FRONT</code> policy moves a
+	 * hovered-over item to the end of its <code>parent</code> container's
+	 * children list, such that it is drawn over its sibling items. Upon roll-out
+	 * the item is left at the top of the list, such that the order of items
+	 * partially reflects the order of mouse visits. The
+	 * <code>MOVE_AND_RETURN</code> policy moves items to the top as well, but
+	 * returns them to their original index upon roll-out.</p>
+	 * 
+	 * @see flare.vis.events.SelectionEvent
+	 */
+	public class HoverControl extends Control
+	{
+		/** Constant indicating that objects hovered over should not be moved
+		 *  within their parent container changed. */
+		public static const DONT_MOVE:int = 0;
+		/** Constant indicating that objects hovered over should be moved to
+		 *  the front of their parent container and kept there. */
+		public static const MOVE_TO_FRONT:int = 1;
+		/** Constant indicating that objects hovered over should be moved to
+		 *  the front of their parent container and then returned to their
+		 *  previous position when the mouse rolls out. */
+		public static const MOVE_AND_RETURN:int = 2;
+		
+		private var _cur:DisplayObject;
+		private var _idx:int;
+		private var _movePolicy:int;
+		
+		/** The policy for moving items forward when highlighted.
+		 *  One of <code>DONT_MOVE</code>, <code>MOVE_TO_FRONT</code>, or
+		 *  <code>MOVE_AND_RETURN</code>. */
+		public function get movePolicy():int { return _movePolicy; }
+		public function set movePolicy(p:int):void {
+			if (p == _movePolicy) return;
+			if (_cur != null && p != MOVE_TO_FRONT &&
+				_movePolicy == MOVE_AND_RETURN)
+			{
+				_cur.parent.setChildIndex(_cur, _idx);
+			}
+			_movePolicy = p;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new HoverControl.
+		 * @param filter a Boolean-valued filter function indicating which
+		 *  items should trigger hover processing
+		 * @param movePolicy indicates which policy should be used for changing
+		 *  the z-ordering of hovered items. One of DONT_MOVE (the default),
+		 *  MOVE_TO_FRONT, or MOVE_AND_RETURN.
+		 * @param rollOver an optional SelectionEvent listener for roll-overs
+		 * @param rollOut an optional SelectionEvent listener for roll-outs
+		 */
+		public function HoverControl(filter:*=null, movePolicy:int=DONT_MOVE,
+			rollOver:Function=null, rollOut:Function=null)
+		{
+			this.filter = filter;
+			_movePolicy = movePolicy;
+			if (rollOver != null)
+				addEventListener(SelectionEvent.SELECT, rollOver);
+			if (rollOut != null)
+				addEventListener(SelectionEvent.DESELECT, rollOut);
+		}
+		
+		/** @inheritDoc */
+		public override function attach(obj:InteractiveObject):void
+		{
+			super.attach(obj);
+			if (obj != null) {
+				obj.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
+				obj.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function detach():InteractiveObject
+		{
+			if (_object != null) {
+				_object.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
+				_object.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
+			}
+			return super.detach();
+		}
+		
+		private function onMouseOver(evt:MouseEvent):void
+		{
+			var n:DisplayObject = evt.target as DisplayObject;
+			if (n==null || (_filter!=null && !_filter(n))) return;
+			
+			_cur = n;
+			
+			if (_movePolicy != DONT_MOVE && n.parent != null) {
+				var p:DisplayObjectContainer = n.parent;
+				_idx = p.getChildIndex(n);
+				p.setChildIndex(n, p.numChildren-1);
+			}
+			if (hasEventListener(SelectionEvent.SELECT)) {
+				dispatchEvent(
+					new SelectionEvent(SelectionEvent.SELECT, _cur, evt));
+			}
+		}
+		
+		private function onMouseOut(evt:MouseEvent):void
+		{
+			if (_cur == null) return;
+			if (hasEventListener(SelectionEvent.DESELECT)) {
+				dispatchEvent(
+					new SelectionEvent(SelectionEvent.DESELECT, _cur, evt));
+			}
+			if (_movePolicy == MOVE_AND_RETURN) {
+				_cur.parent.setChildIndex(_cur, _idx);
+			}
+			_cur = null;
+		}
+		
+	} // end of class HoverControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/PanZoomControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/PanZoomControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/PanZoomControl.as	(revision 15)
@@ -0,0 +1,157 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.util.Displays;
+	
+	import flash.display.InteractiveObject;
+	import flash.display.Stage;
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+	
+	/**
+	 * Interactive control for panning and zooming a "camera". Any sprite can
+	 * be treated as a camera onto its drawing content and display list
+	 * children. The PanZoomControl allows you to manipulate a sprite's
+	 * transformation matrix (the <code>transform.matrix</code> property) to
+	 * simulate camera movements such as panning and zooming. To pan and
+	 * zoom over a collection of objects, simply add a PanZoomControl for
+	 * the sprite holding the collection.
+	 * 
+	 * <pre>
+	 * var s:Sprite; // a sprite holding a collection of items
+	 * new PanZoomControl().attach(s); // attach pan and zoom controls to the sprite
+	 * </pre>
+	 * <p>Once a PanZoomControl has been created, panning is performed by
+	 * clicking and dragging. Zooming is performed either by scrolling the
+	 * mouse wheel or by clicking and dragging vertically while the control key
+	 * is pressed.</p>
+	 * 
+	 * <p>By default, the PanZoomControl attaches itself to the
+	 * <code>stage</code> to listen for mouse events. This works fine if there
+	 * is only one collection of objects in the display list, but can cause
+	 * trouble if you want to have multiple collections that can be separately
+	 * panned and zoomed. The PanZoomControl constructor takes a second
+	 * argument that specifies a "hit area", a shape in the display list that
+	 * should be used to listen to the mouse events for panning and zooming.
+	 * For example, this could be a background sprite behind the zoomable
+	 * content, to which the "camera" sprite could be added. One can then set
+	 * the <code>scrollRect</code> property to add clipping bounds to the 
+	 * panning and zooming region.</p>
+	 */
+	public class PanZoomControl extends Control
+	{
+		private var px:Number, py:Number;
+		private var dx:Number, dy:Number;
+		private var mx:Number, my:Number;
+		private var _drag:Boolean = false;
+		
+		private var _hit:InteractiveObject;
+		private var _stage:Stage;
+		
+		/** The active hit area over which pan/zoom interactions can be performed. */
+		public function get hitArea():InteractiveObject { return _hit; }
+		public function set hitArea(hitArea:InteractiveObject):void {
+			if (_hit != null) onRemove();
+			_hit = hitArea;
+			if (_object && _object.stage != null) onAdd();
+		}
+		
+		/**
+		 * Creates a new PanZoomControl.
+		 * @param hitArea a display object to use as the hit area for mouse
+		 *  events. For example, this could be a background region over which
+		 *  the panning and zooming should be done. If this argument is null,
+		 *  the stage will be used.
+		 */
+		public function PanZoomControl(hitArea:InteractiveObject=null):void
+		{
+			_hit = hitArea;
+		}
+		
+		/** @inheritDoc */
+		public override function attach(obj:InteractiveObject):void
+		{
+			super.attach(obj);
+			if (obj != null) {
+				obj.addEventListener(Event.ADDED_TO_STAGE, onAdd);
+				obj.addEventListener(Event.REMOVED_FROM_STAGE, onRemove);
+				if (obj.stage != null) onAdd();
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function detach():InteractiveObject
+		{
+			onRemove();
+			_object.removeEventListener(Event.ADDED_TO_STAGE, onAdd);
+			_object.removeEventListener(Event.REMOVED_FROM_STAGE, onRemove);
+			return super.detach();
+		}
+		
+		private function onAdd(evt:Event=null):void
+		{
+			_stage = _object.stage;
+			if (_hit == null) {
+				_hit = _stage;
+			}
+			_hit.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
+			_hit.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
+		}
+		
+		private function onRemove(evt:Event=null):void
+		{
+			_hit.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
+			_hit.removeEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
+		}
+		
+		private function onMouseDown(event:MouseEvent) : void
+		{
+			if (_stage == null) return;
+			if (_hit == _object && event.target != _hit) return;
+
+			_stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
+			_stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
+			
+			px = mx = event.stageX;
+			py = my = event.stageY;
+			_drag = true;
+		}
+			
+		private function onMouseMove(event:MouseEvent) : void
+		{
+			if (!_drag) return;
+			
+			var x:Number = event.stageX;
+			var y:Number = event.stageY;
+			
+			if (!event.ctrlKey) {
+				dx = dy = NaN;
+				Displays.panBy(_object, x-mx, y-my);
+			} else {
+				if (isNaN(dx)) {
+					dx = event.stageX;
+					dy = event.stageY;
+				}
+				var dz:Number = 1 + (y-my)/100;
+				Displays.zoomBy(_object, dz, dx, dy);
+			}
+			mx = x;
+			my = y;
+		}
+		
+		private function onMouseUp(event:MouseEvent) : void
+		{
+			dx = dy = NaN;
+			_drag = false;
+			_stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
+			_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
+		}
+		
+		private function onMouseWheel(event:MouseEvent) : void
+		{
+			var dw:Number = 1.1 * event.delta;
+			var dz:Number = dw < 0 ? 1/Math.abs(dw) : dw;
+			Displays.zoomBy(_object, dz);
+		}
+		
+	} // end of class PanZoomControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ClickControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ClickControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ClickControl.as	(revision 15)
@@ -0,0 +1,123 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.vis.events.SelectionEvent;
+	
+	import flash.display.DisplayObject;
+	import flash.display.InteractiveObject;
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+	import flash.events.TimerEvent;
+	import flash.utils.Timer;
+	
+	[Event(name="select",   type="flare.vis.events.SelectionEvent")]
+	[Event(name="deselect", type="flare.vis.events.SelectionEvent")]
+	
+	/**
+	 * Interactive control for responding to mouse clicks events. Select event
+	 * listeners can be added to respond to the mouse clicks. This control
+	 * also allows the number of mouse-clicks (single, double, triple, etc) and
+	 * maximum delay time between clicks to be configured.
+	 * @see flare.vis.events.SelectionEvent
+	 */
+	public class ClickControl extends Control
+	{
+		private var _timer:Timer;
+		private var _cur:DisplayObject;
+		private var _clicks:uint = 0;
+		private var _clear:Boolean = false;
+		private var _evt:MouseEvent = null;
+		
+		/** The number of clicks needed to trigger a click event. Setting this
+		 *  value to zero effectively disables the click control. */
+		public var numClicks:uint;
+		
+		/** The maximum allowed delay (in milliseconds) between clicks. 
+		 *  The delay determines the maximum time interval between a
+		 *  mouse up event and a subsequent mouse down event. */
+		public function get clickDelay():Number { return _timer.delay; }
+		public function set clickDelay(d:Number):void { _timer.delay = d; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new ClickControl.
+		 * @param filter a Boolean-valued filter function indicating which
+		 *  items should trigger hover processing
+		 * @param numClicks the number of clicks
+		 * @param onClick an optional SelectionEvent listener for click events
+		 */
+		public function ClickControl(filter:*=null, numClicks:uint=1,
+			onClick:Function=null, onClear:Function=null)
+		{
+			this.filter = filter;
+			this.numClicks = numClicks;
+			_timer = new Timer(150);
+			_timer.addEventListener(TimerEvent.TIMER, onTimer);
+			if (onClick != null)
+				addEventListener(SelectionEvent.SELECT, onClick);
+			if (onClear != null)
+				addEventListener(SelectionEvent.DESELECT, onClear);
+		}
+		
+		/** @inheritDoc */
+		public override function attach(obj:InteractiveObject):void
+		{
+			if (obj==null) { detach(); return; }
+			super.attach(obj);
+			if (obj != null) {
+				obj.addEventListener(MouseEvent.CLICK, onClick);
+				obj.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function detach():InteractiveObject
+		{
+			if (_object != null) {
+				_object.removeEventListener(MouseEvent.CLICK, onClick);
+				_object.removeEventListener(MouseEvent.MOUSE_DOWN, onDown);
+			}
+			return super.detach();
+		}
+		
+		// -----------------------------------------------------
+		
+		private function onDown(evt:MouseEvent):void
+		{
+			_timer.stop();
+		}
+		
+		private function onClick(evt:MouseEvent):void
+		{
+			var n:DisplayObject = evt.target as DisplayObject;
+			if (n==null || (_filter!=null && !_filter(n))) {
+				_clicks++;
+				_clear = true;
+			} else if (_cur != n) {
+				_clear = false;
+				_clicks = 1;
+				_cur = n;
+			} else {
+				_clicks++;
+			}
+			_evt = evt;
+			_timer.start();
+		}
+		
+		private function onTimer(evt:Event=null):void
+		{
+			if (_clicks == numClicks && _cur) {
+				var type:String = _clear ? SelectionEvent.DESELECT 
+				                         : SelectionEvent.SELECT;
+				if (hasEventListener(type))
+					dispatchEvent(new SelectionEvent(type, _cur, _evt));
+				if (_clear) _cur = null;
+			}
+			_timer.stop();
+			_clicks = 0;
+			_evt = null;
+			_clear = false;
+		}
+		
+	} // end of class ClickControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/SelectionControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/SelectionControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/SelectionControl.as	(revision 15)
@@ -0,0 +1,259 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.vis.events.SelectionEvent;
+	
+	import flash.display.DisplayObject;
+	import flash.display.DisplayObjectContainer;
+	import flash.display.Graphics;
+	import flash.display.InteractiveObject;
+	import flash.display.Shape;
+	import flash.display.Stage;
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+	import flash.geom.Rectangle;
+	import flash.utils.Dictionary;
+
+	[Event(name="select",   type="flare.vis.events.SelectionEvent")]
+	[Event(name="deselect", type="flare.vis.events.SelectionEvent")]
+	
+	/**
+	 * Interactive control for selecting a group of objects by "rubber-banding"
+	 * them with a rectangular section region.
+	 */
+	public class SelectionControl extends Control
+	{
+		private var _r:Rectangle = new Rectangle();
+		private var _drag:Boolean = false;
+		private var _shape:Shape = new Shape();
+		private var _hit:InteractiveObject;
+		private var _stage:Stage;
+		private var _sel:Dictionary = new Dictionary();
+		
+		private var _add0:DisplayObject = null;
+		private var _rem0:DisplayObject = null;
+		private var _add:Array = null;
+		private var _rem:Array = null;
+		
+		/** The active hit area over which selection
+		 *  interactions can be performed. */
+		public function get hitArea():InteractiveObject { return _hit; }
+		public function set hitArea(hitArea:InteractiveObject):void {
+			if (_hit != null) onRemove();
+			_hit = hitArea;
+			if (_object && _object.stage != null) onAdd();
+		}
+		
+		/** Indicates if a selection events should be fired immediately upon a
+		 *  chane of selection status (true) or after the mouse is released
+		 * (false). The default is true. Set this to false if immediate
+		 * selections are causing any performance issues. */
+		public var fireImmediately:Boolean = true;
+		
+		/** Line color of the selection region border. */
+		public var lineColor:uint = 0x8888FF;
+		/** Line alpha of the selection region border. */
+		public var lineAlpha:Number = 0.4;
+		/** Line width of the selection region border. */
+		public var lineWidth:Number = 2;
+		/** Fill color of the selection region. */
+		public var fillColor:uint = 0x8888FF;
+		/** Fill alpha of the selection region. */
+		public var fillAlpha:Number = 0.2;
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new SelectionControl.
+		 * @param filter an optional Boolean-valued filter determining which
+		 *  items are eligible for selection.
+		 * @param hitArea a display object to use as the hit area for mouse
+		 *  events. For example, this could be a background region over which
+		 *  the selection can done. If this argument is null,
+		 *  the stage will be used.
+		 * @param select an optional SelectionEvent listener for selections
+		 * @param deselect an optional SelectionEvent listener for deselections
+		 */
+		public function SelectionControl(filter:*=null,
+			select:Function=null, deselect:Function=null,
+			hitArea:InteractiveObject=null)
+		{
+			_hit = hitArea;
+			this.filter = filter;
+			if (select != null)
+				addEventListener(SelectionEvent.SELECT, select);
+			if (deselect != null)
+				addEventListener(SelectionEvent.DESELECT, deselect);
+		}
+		
+		/**
+		 * Indicates is a display object has been selected. 
+		 * @param d the display object
+		 * @return true if selected, false if not
+		 */
+		public function isSelected(d:DisplayObject):Boolean
+		{
+			return _sel[d] != undefined;
+		}
+		
+		// -----------------------------------------------------
+		
+		/** @inheritDoc */
+		public override function attach(obj:InteractiveObject):void
+		{
+			if (obj==null) { detach(); return; }
+			if (!(obj is DisplayObjectContainer)) {
+				throw new Error("Attached object must be a DisplayObjectContainer");
+			}
+			super.attach(obj);
+			if (obj != null) {
+				obj.addEventListener(Event.ADDED_TO_STAGE, onAdd);
+				obj.addEventListener(Event.REMOVED_FROM_STAGE, onRemove);
+				if (obj.stage != null) onAdd();
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function detach():InteractiveObject
+		{
+			onRemove();
+			if (_object != null) {
+				_object.removeEventListener(Event.ADDED_TO_STAGE, onAdd);
+				_object.removeEventListener(Event.REMOVED_FROM_STAGE, onRemove);
+			}
+			_hit = null;
+			return super.detach();
+		}
+		
+		private function onAdd(evt:Event=null):void
+		{
+			_stage = _object.stage;
+			if (_hit == null) _hit = _stage;
+			_hit.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
+		}
+		
+		private function onRemove(evt:Event=null):void
+		{
+			if (_hit)
+				_hit.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
+		}
+		
+		// -----------------------------------------------------
+				
+		private function mouseDown(evt:MouseEvent):void
+		{
+			if (_stage == null) return;
+			_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
+			_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
+			
+			_r.x = _object.mouseX;
+			_r.y = _object.mouseY;
+			_r.width = 0;
+			_r.height = 1;
+			_drag = true;
+			
+			DisplayObjectContainer(_object).addChild(_shape);
+			renderShape(_shape.graphics);
+			if (fireImmediately) {
+				selectionTest(evt);
+			}
+		}
+		
+		private function mouseMove(evt:MouseEvent):void
+		{
+			if (!_drag) return;
+			_r.width = _object.mouseX - _r.x;
+			_r.height = _object.mouseY - _r.y;
+			
+			renderShape(_shape.graphics);
+			if (fireImmediately) {
+				selectionTest(evt);
+			}
+		}
+		
+		private function mouseUp(evt:MouseEvent):void
+		{
+			if (!fireImmediately)
+				selectionTest(evt);
+			_drag = false;
+			DisplayObjectContainer(_object).removeChild(_shape);
+			_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
+			_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
+		}
+		
+		private function renderShape(g:Graphics):void {
+			g.clear();
+			g.beginFill(fillColor, fillAlpha);
+			g.lineStyle(lineWidth, lineColor, lineAlpha, true, "none");
+			g.drawRect(_r.x, _r.y, _r.width, _r.height);
+			g.endFill();
+		}
+		
+		private function selectionTest(evt:MouseEvent):void {			
+			var con:DisplayObjectContainer = DisplayObjectContainer(_object);
+			for (var i:uint=0; i<con.numChildren; ++i) {
+				walkTree(con.getChildAt(i), test);
+			}
+			
+			// process selection events
+			if (_rem0 && hasEventListener(SelectionEvent.DESELECT)) {
+				dispatchEvent(new SelectionEvent(SelectionEvent.DESELECT,
+					_rem ? _rem : _rem0, evt));
+			}
+			if (_add0 && hasEventListener(SelectionEvent.SELECT)) {
+				dispatchEvent(new SelectionEvent(SelectionEvent.SELECT,
+					_add ? _add : _add0, evt));
+			}
+			_rem = _add = null;
+			_rem0 = _add0 = null;
+		}
+		
+		private static function walkTree(obj:DisplayObject, func:Function):void
+		{
+			func(obj);
+			if (obj is DisplayObjectContainer) {
+				var con:DisplayObjectContainer = obj as DisplayObjectContainer;
+				for (var i:int=0; i<con.numChildren; ++i) {
+					walkTree(con.getChildAt(i), func);
+				}
+			}
+		}
+		
+		private function test(d:DisplayObject):void
+		{
+			if (_filter!=null && !_filter(d)) return;
+			var a:Boolean = _sel[d] != undefined;
+			var b:Boolean = d.hitTestObject(_shape);
+			
+			if (!a && b && hasEventListener(SelectionEvent.SELECT)) {
+				select(d);
+			} else if (a && !b && hasEventListener(SelectionEvent.DESELECT)) {
+				deselect(d);
+			}
+		}
+		
+		private function select(d:DisplayObject):void {
+			_sel[d] = d;
+			if (_add == null)
+				if (_add0 == null) {
+					_add0 = d;
+				} else {
+					_add = [_add0, d];
+				}
+			else
+				_add.push(d);
+		}
+		
+		private function deselect(d:DisplayObject):void {
+			delete _sel[d];
+			if (_rem == null)
+				if (_rem0 == null) {
+					_rem0 = d;
+				} else {
+					_rem = [_rem0, d];
+				}
+			else
+				_rem.push(d);
+		}
+		
+	} // end of class SelectionControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/IControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/IControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/IControl.as	(revision 15)
@@ -0,0 +1,27 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import flash.display.InteractiveObject;
+	
+	import mx.core.IMXMLObject;
+	
+	public interface IControl extends IMXMLObject
+	{
+		/** The interactive object this control is attached to. */
+		function get object():InteractiveObject;
+		
+		/**
+		 * Attach this control to the given interactive object. This method
+		 * will automatically detach if already attached to another object.
+		 * @param obj the display object to attach to
+		 */
+		function attach(obj:InteractiveObject):void;
+		
+		/**
+		 * Detach this control.
+		 * @return the interactive object this control was attached to,
+		 *  or null if this control was not attached.
+		 */
+		function detach():InteractiveObject;
+		
+	} // end of interface IControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/AnchorControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/AnchorControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/AnchorControl.as	(revision 15)
@@ -0,0 +1,74 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.operator.layout.Layout;
+	
+	import flash.display.InteractiveObject;
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+	import flash.geom.Point;
+	
+	/**
+	 * Interactive control for updating a layout's anchor point in response
+	 * to mouse movement. This control is often used to dynamically update a
+	 * focus+context distortion.
+	 */
+	public class AnchorControl extends Control
+	{
+		private var _layout:Layout;
+		
+		public function get layout():Layout { return _layout; }
+		public function set layout(l:Layout):void { _layout = l; }
+		
+		/** Update function called when the layout anchor changes. */
+		public var update:Function = function():void {
+			Visualization(_object).update();
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new AnchorControl
+		 * @param layout the layout on which to update the anchor point
+		 */
+		public function AnchorControl(layout:Layout=null)
+		{
+			_layout = layout;
+		}
+		
+		/** @inheritDoc */
+		public override function attach(obj:InteractiveObject):void
+		{
+			super.attach(obj);
+			if (obj != null) {
+				obj.addEventListener(Event.ENTER_FRAME, updateMouse);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function detach():InteractiveObject
+		{
+			if (_object != null) {
+				_object.removeEventListener(Event.ENTER_FRAME, updateMouse);
+			}
+			return super.detach();
+		}
+		
+		/**
+		 * Causes the layout anchor to be updated according to the current
+		 * mouse position.
+		 * @param evt an optional mouse event
+		 */
+		public function updateMouse(evt:Event=null):void
+		{
+			// get current anchor, run update if changed
+			var p1:Point = _layout.layoutAnchor;
+			_layout.layoutAnchor = new Point(_object.mouseX, _object.mouseY);
+			// distortion might snap the anchor to the layout bounds
+			// so we need to re-retrieve the point to ensure accuracy
+			var p2:Point = _layout.layoutAnchor;
+			if (p1.x != p2.x || p1.y != p2.y) update();
+		}
+		
+	} // end of class AnchorControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/TooltipControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/TooltipControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/TooltipControl.as	(revision 15)
@@ -0,0 +1,269 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.animate.Tween;
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.vis.events.TooltipEvent;
+	
+	import flash.display.DisplayObject;
+	import flash.display.DisplayObjectContainer;
+	import flash.display.InteractiveObject;
+	import flash.display.Stage;
+	import flash.events.MouseEvent;
+	import flash.events.TimerEvent;
+	import flash.filters.DropShadowFilter;
+	import flash.geom.Rectangle;
+	import flash.text.TextFormat;
+	import flash.utils.Timer;
+
+	[Event(name="show", type="flare.vis.events.TooltipEvent")]
+	[Event(name="hide", type="flare.vis.events.TooltipEvent")]
+	[Event(name="update", type="flare.vis.events.TooltipEvent")]
+
+	/**
+	 * Interactive control for displaying a tooltip in response to mouse
+	 * hovers exceeding a minimum time interval. By default, a 
+	 * <code>flare.display.TextSprite</code> instance is used to show a
+	 * tooltip. To change the tooltip text, clients can set either the
+	 * <code>text</code> or <code>htmlText</code> properties of this
+	 * <code>TextSprite</code>. For example:
+	 * 
+	 * <pre>
+	 * // create a new tooltip control and set the text
+	 * var ttc:TooltipControl = new TooltipControl();
+	 * TextSprite(ttc.tooltip).text = "The tooltip text";
+	 * </pre>
+	 * 
+	 * <p>Furthermore, this control fires events corresponding to tooltip show,
+	 * update (move), and hide events. Listeners can be added to dynamically
+	 * change the tooltip text when these events occur. Additionally, the
+	 * default text tooltip can be replaced with an arbitrary
+	 * <code>DisplyObject</code> to provide completely customized tooltips.</p>
+	 * 
+	 * @see flare.vis.events.TooltipEvent
+	 * @see flare.display.TextSprite
+	 */
+	public class TooltipControl extends Control
+	{		
+		private var _cur:DisplayObject;
+		
+		private var _showTimer:Timer;
+		private var _hideTimer:Timer;
+		private var _show:Boolean = false;
+		private var _t:Tween;
+		
+		/** The tooltip delay, in milliseconds. */
+		public function get showDelay():Number { return _showTimer.delay; }
+		public function set showDelay(d:Number):void { _showTimer.delay = d; }
+		
+		/** The delay before hiding a tooltip, in milliseconds. */
+		public function get hideDelay():Number { return _hideTimer.delay; }
+		public function set hideDelay(d:Number):void { _hideTimer.delay = d; }
+		
+		/** The legal bounds for the tooltip in stage coordinates.
+		 *  If null (the default), the full stage bounds are used. */
+		public var tipBounds:Rectangle = null;
+		
+		/** The x-offset from the mouse at which to place the tooltip. */
+		public var xOffset:Number = 0;
+		/** The y-offset from the mouse at which to place the tooltip. */
+		public var yOffset:Number = 25;
+		
+		/** The display object presented as a tooltip. */
+		public var tooltip:DisplayObject = null;
+		
+		/** Duration of fade animations (in seconds) for tooltip show and hide.
+		 *  If less than or equal to zero, no fade will be performed. */
+		public var fadeDuration:Number = 0.3;
+		
+		/** Indicates if the tooltip should follow the mouse pointer. */
+		public var followMouse:Boolean = true;
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new TooltipControl.
+		 * @param filter a Boolean-valued filter function indicating which
+		 *  items should receive tooltip handling
+		 */
+		public function TooltipControl(filter:*=null,
+			tooltip:DisplayObject=null, show:Function=null,
+			update:Function=null, hide:Function=null, delay:Number=500)
+		{
+			this.filter = filter;
+			_showTimer = new Timer(delay);
+			_showTimer.addEventListener(TimerEvent.TIMER, onShow);
+			_hideTimer = new Timer(100);
+			_hideTimer.addEventListener(TimerEvent.TIMER, onHide);
+			
+			this.tooltip = tooltip ? tooltip : createDefaultTooltip();
+
+			if (show != null) addEventListener(TooltipEvent.SHOW, show);
+			if (update != null) addEventListener(TooltipEvent.UPDATE, update);
+			if (hide != null) addEventListener(TooltipEvent.HIDE, hide);
+		}
+		
+		/**
+		 * Generates a default TextSprite tooltip 
+		 * @return a new default tooltip object
+		 */
+		public static function createDefaultTooltip():TextSprite
+		{
+			var fmt:TextFormat = new TextFormat("Arial", 14);
+			fmt.leftMargin = 2;
+			fmt.rightMargin = 2;
+			
+			var tip:TextSprite;
+			tip = new TextSprite("", fmt);
+			tip.textField.border = true;
+			tip.textField.borderColor = 0;
+			tip.textField.background = true;
+			tip.textField.backgroundColor = 0xf5f5cc;
+			tip.textField.multiline = true;
+			tip.filters = [new DropShadowFilter(4,45,0,0.5)];
+			return tip;
+		}
+		
+		/**
+		 * Calculates the tooltip layout.
+		 * @param tip the tooltip object
+		 * @param obj the currently moused-over object
+		 */
+		protected function layout(tip:DisplayObject, obj:DisplayObject):void
+		{
+			var s:Stage = tip.stage;
+			tip.x = s.mouseX + xOffset;
+			tip.y = s.mouseY + yOffset;
+			
+			var b:Rectangle = tipBounds ? tipBounds : getStageBounds(s);
+			var r:Rectangle = tip.getBounds(s);
+			
+			if (r.width > b.width) {
+				tip.x = b.left;
+			} else if (r.left < b.left + 5) {
+				tip.x = s.mouseX + xOffset;
+			} else if (r.right > b.right - 5) {
+				tip.x = s.mouseX - 2 - r.width;
+			}
+			if (r.height > b.height) {
+				tip.y = b.top;
+			} if (r.top < b.top + 5) {
+				tip.y = s.mouseY - yOffset;
+			} else if (r.bottom > b.bottom - 5) {
+				tip.y = s.mouseY - 7 - r.height;
+			}
+		}
+		
+		/** @private */
+		protected function fireEvent(type:String):void
+		{
+			if (hasEventListener(type)) {
+				dispatchEvent(new TooltipEvent(type, _cur, tooltip));
+			}
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/** @inheritDoc */
+		public override function attach(obj:InteractiveObject):void
+		{
+			if (!(obj is DisplayObjectContainer)) {
+				throw new Error("TooltipControls can only be " +
+					"attached to DisplayObjectContainers.");
+			}
+			super.attach(obj);
+			if (obj != null) {
+				obj.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
+				obj.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function detach():InteractiveObject
+		{
+			if (_object != null) {
+				_object.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
+				_object.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
+			}
+			return super.detach();
+		}
+		
+		private function onMouseOver(evt:MouseEvent):void
+		{
+			var n:DisplayObject = evt.target as DisplayObject;
+			if (n==null || (_filter!=null && !_filter(n))) return;
+
+			_cur = n;
+			if (_show) {
+				_hideTimer.stop();
+				onShow();
+			} else {
+				_showTimer.start();
+			}
+		}
+		
+		private function onMouseMove(evt:MouseEvent):void
+		{
+			if (!followMouse) {
+				_object.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
+				return;
+			}
+			fireEvent(TooltipEvent.UPDATE);
+			layout(tooltip, _cur);
+		}
+		
+		private function onShow(evt:TimerEvent=null):void
+		{
+			if (_t && _t.running) _t.stop();
+			_showTimer.stop();
+			_show = true;
+
+			_cur.stage.addChild(tooltip);
+			fireEvent(TooltipEvent.SHOW);
+			layout(tooltip, _cur);
+			
+			if (fadeDuration <= 0) {
+				tooltip.alpha = 1;
+				tooltip.visible = true;
+			} else {
+				_t = new Tween(tooltip, fadeDuration, {alpha:1, visible:true});
+				_t.play();
+			}
+			if (followMouse)
+				_object.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
+		}
+		
+		private function onHide(evt:TimerEvent=null):void
+		{
+			_hideTimer.stop();
+			fireEvent(TooltipEvent.HIDE);
+			if (fadeDuration <= 0) {
+				tooltip.alpha = 0;
+				tooltip.visible = false;
+				if (tooltip.parent)
+					tooltip.parent.removeChild(tooltip);
+			} else {
+				_t = new Tween(tooltip, fadeDuration,
+						{alpha: 0, visible: false}, true);
+				_t.play();
+			}
+			_show = false;
+			_cur = null;
+		}
+		
+		private function onMouseOut(evt:MouseEvent):void
+		{
+			_showTimer.stop();
+			if (_cur == null) return;
+			_object.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
+			if (_show) _hideTimer.start();
+		}
+		
+		// --------------------------------------------------------------------
+		
+		private static function getStageBounds(stage:Stage):Rectangle 
+		{
+			return new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
+		}
+		
+	} // end of class TooltipControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ControlList.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ControlList.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ControlList.as	(revision 15)
@@ -0,0 +1,170 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	
+	import flash.utils.flash_proxy;
+	import flash.utils.Proxy;
+	
+	import mx.core.IMXMLObject;
+	
+	/**
+	 * A ControlList maintains a sequential chain of controls for interacting
+	 * with a visualization. Controls may perform operations such as selection,
+	 * panning, zooming, and expand/contract. Controls can be added to a
+	 * ControlList using the <code>add</code> method. Once added, controls can be
+	 * retrieved and set using their index in the lists, either with array
+	 * notation (<code>[]</code>) or with the <code>getControlAt</code> and
+	 * <code>setControlAt</code> methods.
+	 */
+	public class ControlList extends Proxy implements IMXMLObject
+	{
+		protected var _vis:Visualization;
+		protected var _list:/*IControl*/Array = [];
+		
+		/** The visualization manipulated by these controls. */
+		public function get visualization():Visualization { return _vis; }
+		public function set visualization(v:Visualization):void { 
+			_vis = v;
+			for each (var ic:IControl in _list) { ic.attach(v);	}
+		}
+		
+		/** An array of the controls contained in the control list. */
+		public function set list(ctrls:Array):void {
+			// first remove all current operators
+			while (_list.length > 0) {
+				removeControlAt(_list.length-1);
+			}
+			// then add the new operators
+			for each (var ic:IControl in ctrls) {
+				add(ic);
+			}
+		}
+		
+		/** The number of controls in the list. */
+		public function get length():uint { return _list.length; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new ControlList.
+		 * @param ops an ordered set of controls to include in the list.
+		 */
+		public function ControlList(...controls) {
+			for each (var ic:IControl in controls) {
+				add(ic);
+			}
+		}
+		
+		/**
+		 * Proxy method for retrieving controls from the internal array.
+		 */
+		flash_proxy override function getProperty(name:*):*
+		{
+    		return _list[name];
+    	}
+
+		/**
+		 * Proxy method for setting controls in the internal array.
+		 */
+    	flash_proxy override function setProperty(name:*, value:*):void
+    	{
+        	if (value is IControl) {
+        		var ic:IControl = IControl(value);
+        		_list[name].detach();
+        		_list[name] = ic;
+        		ic.attach(_vis);
+        	} else {
+        		throw new ArgumentError("Input value must be an IControl.");
+        	}
+    	}
+		
+		/**
+		 * Returns the control at the specified position in the list
+		 * @param i the index into the control list
+		 * @return the requested control
+		 */
+		public function getControlAt(i:uint):IControl
+		{
+			return _list[i];
+		}
+		
+		/**
+		 * Removes the control at the specified position in the list
+		 * @param i the index into the control list
+		 * @return the removed control
+		 */
+		public function removeControlAt(i:uint):IControl
+		{
+			var ic:IControl = Arrays.removeAt(_list, i) as IControl;
+			if (ic) ic.detach();
+			return ic;
+		}
+		
+		/**
+		 * Set the control at the specified position in the list
+		 * @param i the index into the control list
+		 * @param ic the control to place in the list
+		 * @return the control previously at the index
+		 */
+		public function setControlAt(i:uint, ic:IControl):IControl
+		{
+			var old:IControl = _list[i];
+			_list[i] = ic;
+			old.detach();
+			ic.attach(_vis);
+			return old;
+		}
+		
+		/**
+		 * Adds a control to the end of this list.
+		 * @param ic the control to add
+		 */
+		public function add(ic:IControl):void
+		{
+			ic.attach(_vis);
+			_list.push(ic);
+		}
+		
+		/**
+		 * Adds a control at the specified index in the list.
+		 * @param ic the control to add
+		 * @param idx the index into the list
+		 */
+		public function addAt(ic:IControl, idx:int):void
+		{
+			ic.attach(_vis);
+			_list.splice(idx, 0, ic);
+		}
+		
+		/**
+		 * Removes an control from this list.
+		 * @param ic the control to remove
+		 * @return true if the control was found and removed, false otherwise
+		 */
+		public function remove(ic:IControl):IControl
+		{
+			var idx:int = Arrays.remove(_list, ic);
+			if (idx >= 0) ic.detach();
+			return ic;
+		}
+		
+		/**
+		 * Removes all controls from this list.
+		 */
+		public function clear():void
+		{
+			for each (var ic:IControl in _list) { ic.detach(); }
+			Arrays.clear(_list);
+		}
+		
+		// -- MXML ------------------------------------------------------------
+		
+		/** @private */
+		public function initialized(document:Object, id:String):void
+		{
+			// do nothing
+		}
+
+	} // end of class ControlList
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/DragControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/DragControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/DragControl.as	(revision 15)
@@ -0,0 +1,96 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	
+	import flash.display.InteractiveObject;
+	import flash.display.Sprite;
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+	
+	/**
+	 * Interactive control for dragging items. A DragControl will enable
+	 * dragging of all Sprites in a container object by clicking and dragging
+	 * them.
+	 */
+	public class DragControl extends Control
+	{
+		private var _cur:Sprite;
+		private var _mx:Number, _my:Number;
+		
+		/** Indicates if drag should be followed at frame rate only.
+		 *  If false, drag events can be processed faster than the frame
+		 *  rate, however, this may pre-empt other processing. */
+		public var trackAtFrameRate:Boolean = false;
+		
+		/** The active item currently being dragged. */
+		public function get activeItem():Sprite { return _cur; }
+		
+		/**
+		 * Creates a new DragControl.
+		 * @param filter a Boolean-valued filter function determining which
+		 *  items should be draggable.
+		 */		
+		public function DragControl(filter:*=null) {
+			this.filter = filter;
+		}
+		
+		/** @inheritDoc */
+		public override function attach(obj:InteractiveObject):void
+		{
+			super.attach(obj);
+			obj.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
+		}
+		
+		/** @inheritDoc */
+		public override function detach() : InteractiveObject
+		{
+			if (_object != null) {
+				_object.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
+			}
+			return super.detach();
+		}
+		
+		private function onMouseDown(event:MouseEvent) : void {
+			var s:Sprite = event.target as Sprite;
+			if (s==null) return; // exit if not a sprite
+			
+			if (_filter==null || _filter(s)) {
+				_cur = s;
+				_mx = _object.mouseX;
+				_my = _object.mouseY;
+				if (_cur is DataSprite) (_cur as DataSprite).fix();
+
+				_cur.stage.addEventListener(MouseEvent.MOUSE_MOVE, onDrag);
+				_cur.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
+				
+				event.stopPropagation();
+			}
+		}
+		
+		private function onDrag(event:Event) : void {
+			var x:Number = _object.mouseX;
+			if (x != _mx) {
+				_cur.x += (x - _mx);
+				_mx = x;
+			}
+			
+			var y:Number = _object.mouseY;
+			if (y != _my) {
+				_cur.y += (y - _my);
+				_my = y;
+			}
+		}
+		
+		private function onMouseUp(event:MouseEvent) : void {
+			if (_cur != null) {
+				_cur.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
+				_cur.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDrag);
+				
+				if (_cur is DataSprite) (_cur as DataSprite).unfix();
+				event.stopPropagation();
+			}
+			_cur = null;
+		}
+		
+	} // end of class DragControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/Control.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/Control.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/Control.as	(revision 15)
@@ -0,0 +1,60 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.util.Filter;
+	
+	import flash.display.InteractiveObject;
+	import flash.events.EventDispatcher;
+
+	/**
+	 * Base class for interactive controls.
+	 */
+	public class Control extends EventDispatcher implements IControl
+	{
+		/** @private */
+		protected var _object:InteractiveObject;
+		/** @private */
+		protected var _filter:Function;
+		
+		/** Boolean function indicating the items considered by the control.
+		 *  @see flare.util.Filter */
+		public function get filter():Function { return _filter; }
+		public function set filter(f:*):void { _filter = Filter.$(f); }
+		
+		/**
+		 * Creates a new Control
+		 */
+		public function Control() {
+			// do nothing
+		}
+		
+		/** @inheritDoc */
+		public function get object():InteractiveObject
+		{
+			return _object;
+		}
+		
+		/** @inheritDoc */
+		public function attach(obj:InteractiveObject):void
+		{
+			if (_object) detach();
+			_object = obj;
+		}
+		
+		/** @inheritDoc */
+		public function detach():InteractiveObject
+		{
+			var obj:InteractiveObject = _object;
+			_object = null;	
+			return obj;
+		}
+		
+		// -- MXML ------------------------------------------------------------
+		
+		/** @private */
+		public function initialized(document:Object, id:String):void
+		{
+			// do nothing
+		}
+		
+	} // end of class Control
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ExpandControl.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ExpandControl.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/controls/ExpandControl.as	(revision 15)
@@ -0,0 +1,91 @@
+package gssim.gssimstudio.editor.flare.vis.controls
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.display.InteractiveObject;
+	import flash.events.MouseEvent;
+
+	/**
+	 * Interactive control for expaning and collapsing graph or tree nodes
+	 * by clicking them. This control will only work when applied to a
+	 * Visualization instance.
+	 */
+	public class ExpandControl extends Control
+	{
+		private var _cur:NodeSprite;
+		
+		/** Update function invoked after expanding or collapsing an item.
+		 *  By default, invokes the <code>update</code> method on the
+		 *  visualization with a 1-second transitioner. */
+		public var update:Function = function():void {
+			var vis:Visualization = _object as Visualization;
+			if (vis) vis.update(1).play();
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new ExpandControl.
+		 * @param filter a Boolean-valued filter function for determining which
+		 *  item this control will expand or collapse
+		 * @param update function invokde after expanding or collapsing an
+		 *  item.
+		 */		
+		public function ExpandControl(filter:*=null, update:Function=null)
+		{
+			this.filter = filter;
+			if (update != null) this.update = update;
+		}
+		
+		/** @inheritDoc */
+		public override function attach(obj:InteractiveObject):void
+		{
+			if (obj==null) { detach(); return; }
+			if (!(obj is Visualization)) {
+				throw new Error("This control can only be attached to a Visualization");
+			}
+			super.attach(obj);
+			obj.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
+		}
+		
+		/** @inheritDoc */
+		public override function detach():InteractiveObject
+		{
+			if (_object != null) {
+				_object.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
+			}
+			return super.detach();
+		}
+		
+		private function onMouseDown(event:MouseEvent) : void {
+			var s:NodeSprite = event.target as NodeSprite;
+			if (s==null) return; // exit if not a NodeSprite
+			
+			if (_filter==null || _filter(s)) {
+				_cur = s;
+				_cur.stage.addEventListener(MouseEvent.MOUSE_MOVE, onDrag);
+				_cur.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
+			}
+			event.stopPropagation();
+		}
+		
+		private function onDrag(event:MouseEvent) : void {
+			_cur.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
+			_cur.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDrag);
+			_cur = null;
+		}
+		
+		private function onMouseUp(event:MouseEvent) : void {
+			_cur.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
+			_cur.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDrag);
+			_cur.expanded = !_cur.expanded;
+			_cur = null;	
+			event.stopPropagation();
+			
+			update();
+		}
+		
+	} // end of class ExpandControl
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/AxisGridLine.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/AxisGridLine.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/AxisGridLine.as	(revision 15)
@@ -0,0 +1,22 @@
+package gssim.gssimstudio.editor.flare.vis.axis
+{
+	import gssim.gssimstudio.editor.flare.display.LineSprite;
+
+	/**
+	 * Axis grid line in an axis display.
+	 */
+	public class AxisGridLine extends LineSprite
+	{
+		private var _ordinal:int;
+		private var _value:Object;
+
+		/** The ordinal index of this grid line in the list of grid lines. */
+		public function get ordinal():int { return _ordinal; }
+		public function set ordinal(ord:int):void { _ordinal = ord; }
+		
+		/** The data value represented by this axis grid line. */
+		public function get value():Object { return _value; }
+		public function set value(value:Object):void { _value = value; }
+		
+	} // end of class AxisGridLine
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/Axis.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/Axis.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/Axis.as	(revision 15)
@@ -0,0 +1,714 @@
+package gssim.gssimstudio.editor.flare.vis.axis
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.scale.IScaleMap;
+	import gssim.gssimstudio.editor.flare.scale.LinearScale;
+	import gssim.gssimstudio.editor.flare.scale.Scale;
+	import gssim.gssimstudio.editor.flare.scale.ScaleType;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Stats;
+	import gssim.gssimstudio.editor.flare.util.Strings;
+	
+	import flash.display.DisplayObject;
+	import flash.display.Sprite;
+	import flash.geom.Point;
+	import flash.text.TextFormat;
+	import flash.utils.Dictionary;
+
+	/**
+	 * A metric data axis consisting of axis labels and gridlines.
+	 * 
+	 * <p>Axis labels can be configured both in terms of text formatting,
+	 * orientation, and position. Use the <code>labelOffsetX</code> or
+	 * <code>labelOffsetY</code> property to adjust label positioning. For
+	 * example, <code>labelOffsetX = -10;</code> places the anchor point for
+	 * the label ten pixels to the left of the data bounds, whereas
+	 * <code>labelOffsetX = 10;</code> will place the point 10 pixels to the
+	 * right of the data bounds. One could simultaneously adjust the
+	 * <code>horizontalAnchor</code> property to align the labels as desired.
+	 * </p>
+	 * 
+	 * <p>Similarly, axis gridlines can also be configured. The
+	 * <code>lineCapX1</code>, <code>lineCapX2</code>, <code>lineCapY1</code>,
+	 * and <code>lineCapY2</code> properties determine by how much the
+	 * grid lines should exceed the data bounds. For example,
+	 * <code>lineCapX1 = 5</code> causes the grid line to extend an extra
+	 * 5 pixels to the left. Each of these values should be greater than or
+	 * equal to zero.</p>
+	 */
+	public class Axis extends Sprite implements IScaleMap
+	{
+		// children indices
+		private static const LABELS:uint = 1;
+        private static const GRIDLINES:uint = 0;
+		
+		// axis scale
+		private var _prevScale:Scale;
+		// axis settings
+		private var _xa:Number=0, _ya:Number=0;   // start of the axis
+		private var _xb:Number=0, _yb:Number=0;   // end of the axis
+		private var _xaP:Number=0, _yaP:Number=0; // previous start of the axis
+		private var _xbP:Number=0, _ybP:Number=0; // previous end of the axis
+		private var _xd:int, _yd:int;             // axis directions (1 or -1)
+		private var _xlo:Number, _ylo:Number;     // label offsets
+		// gridline settings
+		private var _lineColor:uint = 0xd8d8d8;
+		private var _lineWidth:Number = 0;
+		// label settings
+		private var _numLabels:int = -1;
+		private var _anchorH:int = TextSprite.LEFT;
+		private var _anchorV:int = TextSprite.TOP;
+		private var _labelAngle:Number = 0;
+		private var _labelColor:uint = 0;
+		private var _labelFormat:String = null;
+		private var _labelTextMode:int = TextSprite.BITMAP;
+		private var _labelTextFormat:TextFormat = new TextFormat("Arial",12,0);
+		// temporary variables
+		private var _point:Point = new Point();
+		
+		// -- Properties ------------------------------------------------------
+		
+		/** Sprite containing the axis labels. */
+		public function get labels():Sprite { return getChildAt(LABELS) as Sprite; }
+		/** Sprite containing the axis grid lines. */
+		public function get gridLines():Sprite { return getChildAt(GRIDLINES) as Sprite; }
+		
+		/** @inheritDoc */
+		public function get x1():Number { return _xa; }
+		public function set x1(x:Number):void { _xa = x; }
+		
+		/** @inheritDoc */
+		public function get y1():Number { return _ya; }
+		public function set y1(y:Number):void { _ya = y; }
+		
+		/** @inheritDoc */
+		public function get x2():Number { return _xb; }
+		public function set x2(x:Number):void { _xb = x; }
+		
+		/** @inheritDoc */
+		public function get y2():Number { return _yb; }
+		public function set y2(y:Number):void { _yb = y; }
+
+		/** The Scale used to map values to this axis. */
+		public var axisScale:Scale;
+		
+		/** Flag indicating if axis labels should be shown. */
+		public var showLabels:Boolean = true;
+		
+		/** Flag indicating if labels should be removed in case of overlap. */
+		public var fixLabelOverlap:Boolean = true;
+		
+		/** Flag indicating if axis grid lines should be shown. */
+		public var showLines:Boolean = true;
+		
+		/** X length of axis gridlines. */
+		public var lineLengthX:Number = 0;
+		
+		/** Y length of axis gridlines. */
+		public var lineLengthY:Number = 0;	
+			
+		/** X offset for axis gridlines at the lower end of the axis. */
+		public var lineCapX1:Number = 0;
+		
+		/** X offset for axis gridlines at the upper end of the axis. */
+		public var lineCapX2:Number = 0;
+		
+		/** Y offset for axis gridlines at the lower end of the axis. */
+		public var lineCapY1:Number = 0;
+		
+		/** Y offset for axis gridlines at the upper end of the axis. */
+		public var lineCapY2:Number = 0;
+		
+		/** X-dimension offset value for axis labels. If negative or zero, this
+		 *  value indicates how much to offset to the left of the data bounds.
+		 *  If positive, the offset is made to the right of the data bounds. */
+		public var labelOffsetX:Number = 0;	
+			
+		/** Y-dimension offset value for axis labels. If negative or zero, this
+		 *  value indicates how much to offset above the data bounds.
+		 *  If positive, the offset is made beneath the data bounds.*/
+		public var labelOffsetY:Number = 0;
+		
+		/** The line color of axis grid lines. */
+		public function get lineColor():uint { return _lineColor; }
+		public function set lineColor(c:uint):void { _lineColor = c; updateGridLines(); }
+		
+		/** The line width of axis grid lines. */
+		public function get lineWidth():Number { return _lineWidth; }
+		public function set lineWidth(w:Number):void { _lineWidth = w; updateGridLines(); }
+		
+		/** The color of axis label text. */
+		public function get labelColor():uint { return _labelColor; }
+		public function set labelColor(c:uint):void { _labelColor = c; updateLabels(); }
+		
+		/** The angle (orientation) of axis label text. */
+		public function get labelAngle():Number { return _labelAngle; }
+		public function set labelAngle(a:Number):void { _labelAngle = a; updateLabels(); }
+		
+		/** TextFormat (font, size, style) for axis label text. */
+		public function get labelTextFormat():TextFormat { return _labelTextFormat; }
+		public function set labelTextFormat(f:TextFormat):void { _labelTextFormat = f; updateLabels(); }
+		
+		/** The text rendering mode to use for label TextSprites.
+		 *  @see flare.display.TextSprite. */
+		public function get labelTextMode():int { return _labelTextMode; }
+		public function set labelTextMode(m:int):void { _labelTextMode = m; updateLabels(); }
+		
+		/** String formatting pattern used for axis labels, overwrites any
+		 *  formatting pattern used by the <code>axisScale</code>. If null,
+		 *  the formatting pattern for the <code>axisScale</code> is used. */
+		public function get labelFormat():String {
+			return _labelFormat==null ? null 
+					: _labelFormat.substring(3, _labelFormat.length-1);
+		}
+		public function set labelFormat(fmt:String):void {
+			_labelFormat = "{0:"+fmt+"}"; updateLabels();
+		}
+		
+		/** The number of labels and gridlines to generate by default. If this
+		 *  number is zero or less (default -1), the number of labels will be
+		 *  automatically determined from the current scale and size. */
+		public function get numLabels():int {
+			// if set positive, return number
+			if (_numLabels > 0) return _numLabels;
+			// if ordinal return all labels
+			if (ScaleType.isOrdinal(axisScale.scaleType)) return -1;
+			// otherwise determine based on axis size (random hack...)
+			var lx:Number = _xb-_xa; if (lx<0) lx = -lx;
+			var ly:Number = _yb-_ya; if (ly<0) ly = -ly;
+			lx = (lx > ly ? lx : ly);
+			return lx > 200 ? 10 : lx < 20 ? 1 : int(lx/20);
+		}
+		public function set numLabels(n:int):void { _numLabels = n; }
+		
+		/** The horizontal anchor point for axis labels.
+		 *  @see flare.display.TextSprite. */
+		public function get horizontalAnchor():int { return _anchorH; }
+		public function set horizontalAnchor(a:int):void { _anchorH = a; updateLabels(); }
+		
+		/** The vertical anchor point for axis labels.
+		 *  @see flare.display.TextSprite. */
+		public function get verticalAnchor():int { return _anchorV; }
+		public function set verticalAnchor(a:int):void { _anchorV = a; updateLabels(); }		
+		
+		/** The x-coordinate of the axis origin. */
+		public function get originX():Number {
+			return (ScaleType.isQuantitative(axisScale.scaleType) ? X(0) : x1);
+		}
+		/** The y-coordinate of the axis origin. */
+		public function get originY():Number {
+			return (ScaleType.isQuantitative(axisScale.scaleType) ? Y(0) : y1);
+		}
+		
+		// -- Initialization --------------------------------------------------
+		
+		/**
+		 * Creates a new Axis.
+		 * @param axisScale the axis scale to use. If null, a linear scale
+		 *  is assumed.
+		 */
+		public function Axis(axisScale:Scale=null)
+        {
+            this.axisScale = axisScale ? axisScale : new LinearScale();
+            _prevScale = this.axisScale;
+            initializeChildren();
+        }
+
+		/**
+		 * Initializes the child container sprites for labels and grid lines.
+		 */
+        protected function initializeChildren():void
+        {
+            addChild(new Sprite()); // add gridlines
+            addChild(new Sprite()); // add labels
+        }
+		
+		// -- Updates ---------------------------------------------------------
+		
+		/**
+		 * Updates this axis, performing filtering and layout as needed.
+		 * @param trans a Transitioner for collecting value updates
+		 * @return the input transitioner.
+		 */
+		public function update(trans:Transitioner):Transitioner
+        {
+        	var t:Transitioner = (trans!=null ? trans : Transitioner.DEFAULT);
+        	
+        	// compute directions and offsets
+        	_xd  = lineLengthX < 0 ? -1 : 1;
+        	_yd  = lineLengthY < 0 ? -1 : 1;
+        	_xlo =  _xd*labelOffsetX + (labelOffsetX>0 ? lineLengthX : 0);
+        	_ylo = -_yd*labelOffsetY + (labelOffsetY<0 ? lineLengthY : 0);
+        	
+        	// run updates
+            filter(t);
+            layout(t);
+            updateLabels(); // TODO run through transitioner?
+            updateGridLines(); // TODO run through transitioner?
+            return trans;
+        }
+		
+		// -- Lookups ---------------------------------------------------------
+		
+		/**
+		 * Returns the horizontal offset along the axis for the input value.
+		 * @param value an input data value
+		 * @return the horizontal offset along the axis corresponding to the
+		 *  input value. This is the x-position minus <code>x1</code>.
+		 */
+		public function offsetX(value:Object):Number
+        {
+        	return axisScale.interpolate(value) * (_xb - _xa);
+        }
+        
+        /**
+		 * Returns the vertical offset along the axis for the input value.
+		 * @param value an input data value
+		 * @return the vertical offset along the axis corresponding to the
+		 *  input value. This is the y-position minus <code>y1</code>.
+		 */
+        public function offsetY(value:Object):Number
+        {
+        	return axisScale.interpolate(value) * (_yb - _ya);
+        }
+
+		/** @inheritDoc */
+		public function X(value:Object):Number
+        {
+        	return _xa + offsetX(value);
+        }
+        
+        /** @inheritDoc */
+        public function Y(value:Object):Number
+        {
+        	return _ya + offsetY(value);
+        }
+        
+        /** @inheritDoc */
+        public function value(x:Number, y:Number, stayInBounds:Boolean=true):Object
+        {
+        	// project the input point onto the axis line
+        	// (P-A).(B-A) / |B-A|^2 == fractional projection onto axis line
+        	var dx:Number = (_xb-_xa);
+        	var dy:Number = (_yb-_ya);
+        	var f:Number = ((x-_xa)*dx + (y-_ya)*dy) / (dx*dx + dy*dy);
+        	// correct bounds, if desired
+        	if (stayInBounds) {
+        		if (f < 0) f = 0;
+        		if (f > 1) f = 1;
+        	}
+        	// lookup and return value
+        	return axisScale.lookup(f);
+        }
+		
+		/**
+		 * Clears the previous axis scale used, if cached.
+		 */
+		public function clearPreviousScale():void
+		{
+			_prevScale = axisScale;
+		}
+		
+		// -- Filter ----------------------------------------------------------
+		
+		/**
+		 * Performs filtering, determining which axis labels and grid lines
+		 * should be visible.
+		 * @param trans a Transitioner for collecting value updates.
+		 */
+		protected function filter(trans:Transitioner) : void
+		{
+			var ordinal:uint = 0, i:uint, idx:int = -1, val:Object;
+			var label:AxisLabel = null;
+			var gline:AxisGridLine = null;
+			var nl:uint = labels.numChildren;
+			var ng:uint = gridLines.numChildren;
+			
+			var keepLabels:Array = new Array(nl);
+			var keepLines:Array = new Array(ng);
+			var values:Array = axisScale.values(numLabels);
+			
+			if (showLabels) { // process labels
+				for (i=0, ordinal=0; i<values.length; ++i) {
+					val = values[i];
+					if ((idx = findLabel(val, nl)) < 0) {
+						label = createLabel(val);
+					} else {
+						label = labels.getChildAt(idx) as AxisLabel;
+						keepLabels[idx] = true;
+					}
+					label.ordinal = ordinal++;
+				}
+			}
+			if (showLines) { // process gridlines
+				for (i=0, ordinal=0; i<values.length; ++i) {
+					val = values[i];
+					if ((idx = findGridLine(val, ng)) < 0) {
+						gline = createGridLine(val);
+					} else {
+						gline = gridLines.getChildAt(idx) as AxisGridLine;
+						keepLines[idx] = true;
+					}
+					gline.ordinal = ordinal++;
+				}
+			}
+			markRemovals(trans, keepLabels, labels);
+			markRemovals(trans, keepLines, gridLines);
+		}
+		
+		/**
+		 * Marks all items slated for removal from this axis.
+		 * @param trans a Transitioner for collecting value updates.
+		 * @param keep a Boolean array indicating which items to keep
+		 * @param con a container Sprite whose contents should be marked
+		 *  for removal
+		 */
+		protected function markRemovals(trans:Transitioner, keep:Array, con:Sprite) : void
+		{
+			for (var i:uint = keep.length; --i >= 0; ) {
+				if (!keep[i]) trans.removeChild(con.getChildAt(i));
+			}
+		}
+		
+		// -- Layout ----------------------------------------------------------
+		
+		/**
+		 * Performs layout, setting the position of labels and grid lines.
+		 * @param trans a Transitioner for collecting value updates.
+		 */
+		protected function layout(trans:Transitioner) : void
+		{
+			var i:uint, label:AxisLabel, gline:AxisGridLine, p:Point;
+			var _lab:Sprite = this.labels;
+			var _gls:Sprite = this.gridLines;
+			var o:Object;
+			
+			// layout labels
+			for (i=0; i<_lab.numChildren; ++i) {
+				label = _lab.getChildAt(i) as AxisLabel;
+				p = positionLabel(label, axisScale);
+				
+				o = trans.$(label);
+				o.x = p.x;
+				o.y = p.y;
+				o.alpha = trans.willRemove(label) ? 0 : 1;
+			}
+			// fix label overlap
+			if (fixLabelOverlap) fixOverlap(trans);
+			// layout gridlines
+			for (i=0; i<_gls.numChildren; ++i) {
+				gline = _gls.getChildAt(i) as AxisGridLine;
+				p = positionGridLine(gline, axisScale);
+				
+				o = trans.$(gline);
+				o.x1 = p.x;
+				o.y1 = p.y;
+				o.x2 = p.x + lineLengthX + _xd*(lineCapX1+lineCapX2);
+				o.y2 = p.y + lineLengthY + _yd*(lineCapY1+lineCapY2);
+				o.alpha = trans.willRemove(gline) ? 0 : 1;
+			}
+			// update previous scale
+			_prevScale = axisScale.clone(); // clone scale
+			_xaP = _xa; _yaP = _ya; _xbP = _xb; _ybP = _yb;
+		}
+		
+		// -- Label Overlap ---------------------------------------------------
+		
+		/**
+		 * Eliminates overlap between labels along an axis. 
+		 * @param trans a transitioner, potentially storing label positions
+		 */		
+		protected function fixOverlap(trans:Transitioner):void
+		{
+			var labs:Array = [], d:DisplayObject, i:int;
+			// collect and sort labels
+			for (i=0; i<labels.numChildren; ++i) {
+				var s:AxisLabel = AxisLabel(labels.getChildAt(i));
+				if (!trans.willRemove(s)) labs.push(s);
+			}
+			if (labs.length == 0) return;
+			labs.sortOn("ordinal", Array.NUMERIC);
+			
+			// stores the labels to remove
+			var rem:Dictionary = new Dictionary();
+			
+			if (axisScale.scaleType == ScaleType.LOG) {
+				fixLogOverlap(labs, rem, trans, axisScale);
+			}
+			
+			// maintain min and max if we get down to two
+			i = labs.length;
+			var min:Object = labs[0];
+			var max:Object = labs[i-1];
+			var mid:Object = (i&1) ? labs[(i>>1)] : null;
+
+			// fix overlap with an iterative optimization
+			// remove every other label with each iteration
+			while (hasOverlap(labs, trans)) {
+				// reduce labels
+				i = labs.length;
+				if (mid && i>3 && i<8) { // use min, med, max if we can
+					for each (d in labs) rem[d] = d;
+					if (rem[min]) delete rem[min];
+					if (rem[max]) delete rem[max];
+					if (rem[mid]) delete rem[mid];
+					labs = [min, mid, max];
+				}
+				else if (i < 4) { // use min and max if we're down to two
+					if (rem[min]) delete rem[min];
+					if (rem[max]) delete rem[max];
+					for each (d in labs) {
+						if (d != min && d != max) rem[d] = d;
+					}
+					break;
+				}
+				else { // else remove every odd element
+					i = i - (i&1 ? 2 : 1);
+					for (; i>0; i-=2) {
+						rem[labs[i]] = labs[i];
+						labs.splice(i, 1); // remove from array
+					}
+				}
+			}
+			
+			// remove the deleted labels
+			for each (d in rem) {
+				trans.$(d).alpha = 0;
+				trans.removeChild(d, true);
+			}
+		}
+		
+		private static function fixLogOverlap(labs:Array, rem:Dictionary,
+			trans:Transitioner, scale:Scale):void
+		{
+				var base:int = int(Object(scale).base), i:int, j:int, zidx:int;
+				if (!hasOverlap(labs, trans)) return;
+				
+				// find zero
+				zidx = Arrays.binarySearch(labs, 0, "value");
+				var neg:Boolean = Number(scale.min) < 0;
+				var pos:Boolean = Number(scale.max) > 0;
+				
+				// if includes negative, traverse backwards from zero/end
+				if (neg) {
+					i = (zidx<0 ? labs.length : zidx) - (pos ? 1 : 2);
+					for (j=pos?1:2; i>=0; ++j, --i) {
+						if (j == base) {
+							j = 1;
+						} else {
+							rem[labs[i]] = labs[i];
+							labs.splice(i, 1); --zidx;
+						}
+					}
+				}
+				// if includes positive, traverse forwards from zero/start
+				if (pos) {
+					i = (zidx<0 ? 0 : zidx+1) + (neg ? 0 : 1);
+					for (j=neg?1:2; i<labs.length; ++j) {
+						if (j == base) {
+							j = 1; ++i;
+						} else {
+							rem[labs[i]] = labs[i];
+							labs.splice(i, 1);
+						}
+					}
+				}
+		}
+		
+		private static function hasOverlap(labs:Array, trans:Transitioner):Boolean
+		{
+			var d:DisplayObject = labs[0], e:DisplayObject;
+			for (var i:int=1; i<labs.length; ++i) {
+				if (overlaps(trans, d, (e=labs[i]))) return true;
+				d = e;
+			}
+			return false;
+		}
+		
+		/**
+		 * Indicates if two display objects overlap, sensitive to any target
+		 * values stored in a transitioner.
+		 * @param trans a Transitioner, potentially with target values
+		 * @param l1 a display object
+		 * @param l2 a display object
+		 * @return true if the objects overlap (considering values in the
+		 *  transitioner, if appropriate), false otherwise
+		 */
+		private static function overlaps(trans:Transitioner,
+			l1:DisplayObject, l2:DisplayObject):Boolean
+		{
+			if (trans.immediate) return l1.hitTestObject(l2);
+			// get original co-ordinates
+			var xa:Number = l1.x, ya:Number = l1.y;
+			var xb:Number = l2.x, yb:Number = l2.y;
+			var o:Object;
+			// set to target co-ordinates
+			o = trans.$(l1); l1.x = o.x; l1.y = o.y;
+			o = trans.$(l2); l2.x = o.x; l2.y = o.y;
+			// compute overlap
+			var b:Boolean = l1.hitTestObject(l2);
+			// reset to original coordinates
+			l1.x = xa; l1.y = ya; l2.x = xb; l2.y = yb;
+			return b;
+		}
+		
+		// -- Axis Label Helpers ----------------------------------------------
+		
+		/**
+		 * Creates a new axis label.
+		 * @param val the value to create the label for
+		 * @return an AxisLabel
+		 */		
+		protected function createLabel(val:Object) : AxisLabel
+		{
+			var label:AxisLabel = new AxisLabel();
+			var f:Number = _prevScale.interpolate(val);
+			label.alpha = 0;
+			label.value = val;
+			label.x = _xlo + _xaP + f*(_xbP - _xaP);
+			label.y = _ylo + _yaP + f*(_ybP - _yaP);
+			updateLabel(label);
+			labels.addChild(label);
+			return label;
+		}
+		
+		/**
+		 * Computes the position of an axis label.
+		 * @param label the axis label to layout
+		 * @param scale the scale used to map values to the axis
+		 * @return a Point with x,y coordinates for the axis label
+		 */
+		protected function positionLabel(label:AxisLabel, scale:Scale) : Point
+		{
+			var f:Number = scale.interpolate(label.value);
+			_point.x = _xlo + _xa + f*(_xb-_xa);
+			_point.y = _ylo + _ya + f*(_yb-_ya);
+			return _point;
+		}
+		
+		/**
+		 * Updates an axis label's settings
+		 * @param label the label to update
+		 */		
+		protected function updateLabel(label:AxisLabel) : void
+		{
+			label.textFormat = _labelTextFormat;
+			label.horizontalAnchor = _anchorH;
+			label.verticalAnchor = _anchorV;
+			label.rotation = (180/Math.PI) * _labelAngle;
+			label.textMode = _labelTextMode;
+			label.text = _labelFormat==null ? axisScale.label(label.value)
+					   : Strings.format(_labelFormat, label.value);
+		}
+		
+		/**
+		 * Updates all axis labels.
+		 */		
+		protected function updateLabels() : void
+		{
+			var _labels:Sprite = this.labels;
+			for (var i:uint = 0; i<_labels.numChildren; ++i) {
+				updateLabel(_labels.getChildAt(i) as AxisLabel);
+			}
+		}
+		
+		/**
+		 * Returns the index of a label in the label's container sprite for a
+		 * given data value.
+		 * @param val the data value to find
+		 * @param len the number of labels to check
+		 * @return the index of a label with matching value, or -1 if no label
+		 *  was found
+		 */		
+		protected function findLabel(val:Object, len:uint) : int
+		{
+			var _labels:Sprite = this.labels;
+			for (var i:uint = 0; i < len; ++i) {
+				// TODO: make this robust to repeated values
+				if (Stats.equal((_labels.getChildAt(i) as AxisLabel).value, val)) {
+					return i;
+				}
+			}
+			return -1;
+		}
+		
+		// -- Axis GridLine Helpers -------------------------------------------
+		
+		/**
+		 * Creates a new axis grid line.
+		 * @param val the value to create the grid lines for
+		 * @return an AxisGridLine
+		 */	
+		protected function createGridLine(val:Object) : AxisGridLine
+		{
+			var gline:AxisGridLine = new AxisGridLine();
+			var f:Number = _prevScale.interpolate(val);
+			gline.alpha = 0;
+			gline.value = val;
+			gline.x1 = _xaP + f*(_xbP-_xaP) - _xd*lineCapX1;
+			gline.y1 = _yaP + f*(_ybP-_yaP) - _yd*lineCapY1;
+			gline.x2 = gline.x1 + lineLengthX + _xd*(lineCapX1 + lineCapX2)
+			gline.y2 = gline.y1 + lineLengthY + _yd*(lineCapY1 + lineCapY2);
+			updateGridLine(gline);
+			gridLines.addChild(gline);
+			return gline;
+		}
+		
+		/**
+		 * Computes the position of an axis grid line.
+		 * @param gline the axis grid line to layout
+		 * @param scale the scale used to map values to the axis
+		 * @return a Point with x,y coordinates for the axis grid line
+		 */
+		protected function positionGridLine(gline:AxisGridLine, scale:Scale) : Point
+		{
+			var f:Number = scale.interpolate(gline.value);
+			_point.x = _xa + f*(_xb-_xa) - _xd*lineCapX1;
+			_point.y = _ya + f*(_yb-_ya) - _yd*lineCapY1;
+			return _point;
+		}
+		
+		/**
+		 * Updates an axis grid line's settings
+		 * @param gline the grid line to update
+		 */
+		protected function updateGridLine(gline:AxisGridLine) : void
+		{
+			gline.lineColor = _lineColor;
+			gline.lineWidth = _lineWidth;
+		}
+		
+		/**
+		 * Updates all grid lines.
+		 */
+		protected function updateGridLines() : void
+		{
+			var _glines:Sprite = this.gridLines;
+			for (var i:uint = 0; i<_glines.numChildren; ++i) {
+				updateGridLine(_glines.getChildAt(i) as AxisGridLine);
+			}
+		}
+		
+		/**
+		 * Returns the index of a grid lines in the line's container sprite
+		 * for a given data value.
+		 * @param val the data value to find
+		 * @param len the number of grid lines to check
+		 * @return the index of a grid line with matching value, or -1 if no
+		 *  grid line was found
+		 */	
+		protected function findGridLine(val:Object, len:uint) : int
+		{
+			var _glines:Sprite = this.gridLines;
+			for (var i:uint = 0; i<len; ++i) {
+				// TODO: make this robust to repeated values
+				if (Stats.equal((_glines.getChildAt(i) as AxisGridLine).value, val)) {
+					return i;
+				}
+			}
+			return -1;
+		}
+		
+	} // end of class Axis
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/AxisLabel.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/AxisLabel.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/AxisLabel.as	(revision 15)
@@ -0,0 +1,22 @@
+package gssim.gssimstudio.editor.flare.vis.axis
+{
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	
+	/**
+	 * Axis label in an axis display.
+	 */
+	public class AxisLabel extends TextSprite
+	{
+		private var _ordinal:int;
+		private var _value:Object;
+
+		/** The ordinal index of this axis label in the list of labels. */
+		public function get ordinal():int { return _ordinal; }
+		public function set ordinal(ord:int):void { _ordinal = ord; }
+		
+		/** The data value represented by this axis label. */
+		public function get value():Object { return _value; }
+		public function set value(value:Object):void { _value = value; }
+		
+	} // end of class AxisLabel
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/CartesianAxes.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/CartesianAxes.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/CartesianAxes.as	(revision 15)
@@ -0,0 +1,203 @@
+package gssim.gssimstudio.editor.flare.vis.axis
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.display.RectSprite;
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Axes class representing 2D Cartesian (X-Y) axes.
+	 */
+	public class CartesianAxes extends Axes
+	{
+		// -- Properties ------------------------------------------------------
+				
+		private var _xaxis:Axis;
+		private var _yaxis:Axis;
+		private var _xline:AxisGridLine;
+		private var _yline:AxisGridLine;
+		private var _border:RectSprite;
+		private var _xGridClip:RectSprite;
+		private var _yGridClip:RectSprite;
+		
+		/** Flag indicating if the x-origin line should be shown. */
+		public var showXLine:Boolean;
+		/** Flag indicating if the y-origin line should be shown. */
+		public var showYLine:Boolean;
+		/** Determines if the x-axis should be in reverse order. */
+		public var xReverse:Boolean = false;
+		/** Determines if the y-axis should be in reverse order. */
+		public var yReverse:Boolean = false;
+		
+		/** The x-axis. */
+		public function get xAxis():Axis { return _xaxis; }
+		/** The y-axis. */
+		public function get yAxis():Axis { return _yaxis; }
+		/** Grid line for the origin along the x-axis. */
+		public function get xLine():AxisGridLine { return _xline; }
+		/** Grid line for the origin along the y-axis. */
+		public function get yLine():AxisGridLine { return _yline; }
+				
+		/** The x-coordinate of the axes' origin point. */
+		public function get originX():Number { return _xaxis.originX; }
+		/** The y-coordinate of the axes' origin point. */
+		public function get originY():Number { return _yaxis.originY; }
+		
+		/** Flag indicating if a border for the axes should be shown. */
+		public function get showBorder():Boolean { return _border.visible; }
+		public function set showBorder(b:Boolean):void { _border.visible = b; }
+		
+		/** The axes border color. */
+		public function get borderColor():uint { return _border.lineColor; }
+		public function set borderColor(c:uint):void { _border.lineColor = c; }
+		
+		/** The line width of the axes border. */
+		public function get borderWidth():Number { return _border.lineWidth; }
+		public function set borderWidth(w:Number):void { _border.lineWidth = w; }
+		
+				
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates new CartesianAxes.
+		 * @param vis the visualization the axes correspond to.
+		 */
+		public function CartesianAxes(vis:Visualization=null) {
+			_vis = vis;
+			
+			addChild(_xaxis = new Axis());
+			addChild(_yaxis = new Axis());
+			addChild(_xline = new AxisGridLine());
+			addChild(_yline = new AxisGridLine());
+			addChild(_border = new RectSprite());
+			addChild(_xGridClip = new RectSprite());
+			addChild(_yGridClip = new RectSprite());
+			
+			// set names
+			_xaxis.name = "_xaxis";
+			_yaxis.name = "_yaxis";
+			_xline.name = "_xline";
+			_yline.name = "_yline";
+			_border.name = "_border";
+			
+			// set label anchors
+			_xaxis.horizontalAnchor = TextSprite.CENTER;
+			_xaxis.verticalAnchor   = TextSprite.TOP;
+			_yaxis.horizontalAnchor = TextSprite.RIGHT;
+			_yaxis.verticalAnchor   = TextSprite.MIDDLE;
+            
+            // set default label offsets
+            _xaxis.labelOffsetX =  0; _xaxis.labelOffsetY = 8;
+            _yaxis.labelOffsetX = -8; _yaxis.labelOffsetY = 0;
+
+            // set default gridline caps
+            _xaxis.lineCapX1 = _xaxis.lineCapX2 = 0;
+            _xaxis.lineCapY1 = _xaxis.lineCapY2 = 0;
+            _yaxis.lineCapX1 = _yaxis.lineCapX2 = 0;
+            _yaxis.lineCapY1 = _yaxis.lineCapY2 = 0;
+
+            // set default gridline colors
+            _xaxis.lineColor = 0xd8d8d8;
+            _yaxis.lineColor = 0xd8d8d8;
+
+            // set default line settings
+            _xline.lineColor = 0xcccccc;
+            _yline.lineColor = 0xcccccc;
+            
+            // set up border
+            _border.lineColor = 0xffd8d8d8;
+            _border.fillColor = 0x00ffffff;
+            
+            // set up clipping masks
+            _xGridClip.lineColor = 0;
+            _xGridClip.fillColor = 0xffffffff;
+            _yGridClip.lineColor = 0;
+            _yGridClip.fillColor = 0xffffffff;
+		}
+		
+		/** @inheritDoc */
+		public override function update(trans:Transitioner=null):Transitioner
+        {
+        	var t:Transitioner = (trans!=null ? trans : Transitioner.DEFAULT);
+        	var o:Object;
+        	var b:Rectangle = layoutBounds;
+        	
+        	// set x-axis position
+        	if (xReverse) {
+        		_xaxis.x1 = b.right; _xaxis.y1 = b.bottom;
+        		_xaxis.x2 = b.left;  _xaxis.y2 = b.bottom;
+        	} else {
+        		_xaxis.x1 = b.left;  _xaxis.y1 = b.bottom;
+        		_xaxis.x2 = b.right; _xaxis.y2 = b.bottom;
+        	}
+
+			// set y-axis position
+			if (yReverse) {
+				_yaxis.x1 = b.left;  _yaxis.y1 = b.top;
+        		_yaxis.x2 = b.left;  _yaxis.y2 = b.bottom;
+   			} else {
+   				_yaxis.x1 = b.left;  _yaxis.y1 = b.bottom;
+        		_yaxis.x2 = b.left;  _yaxis.y2 = b.top;
+   			}
+        	
+        	// gridline length
+        	_xaxis.lineLengthX = 0;
+        	_xaxis.lineLengthY = -b.height;
+        	_yaxis.lineLengthX = b.width;
+        	_yaxis.lineLengthY = 0;
+
+			// update axes
+			_xaxis.update(t);
+			_yaxis.update(t);
+
+			// update x-axis origin line
+			var yx:Number = _yaxis.offsetX(0);
+			var yy:Number = _yaxis.offsetY(0);
+			var ys:Boolean = showXLine && yx >= 0 && yx <= b.width;
+			o = t.$(_xline);
+			o.x1 = _xaxis.x1 + yx;
+			o.y1 = _xaxis.y1 + yy;
+			o.x2 = _xaxis.x2 + yx;
+			o.y2 = _xaxis.y2 + yy;
+			o.alpha = ys ? 1 : 0;
+			
+			// update y-axis origin line
+			var xx:Number = _xaxis.offsetX(0);
+			var xy:Number = _xaxis.offsetY(0);
+			var xs:Boolean = showYLine && xy >= 0 && xy <= b.height;
+			o = t.$(_yline);
+			o.x1 = _yaxis.x1 + xx;
+			o.y1 = _yaxis.y1 + xy;
+			o.x2 = _yaxis.x2 + xx;
+			o.y2 = _yaxis.y2 + xy;
+			o.alpha = xs ? 1 : 0;
+
+			// update axis border
+			o = t.$(_border);
+			o.x = b.x;
+			o.y = b.y;
+			o.w = b.width;
+			o.h = b.height;
+			
+			// set the gridline clipping regions			
+			o = t.$(_xGridClip);
+			o.x = b.x;
+			o.y = b.y - _xaxis.lineCapY2;
+			o.w = b.width + 1;
+			o.h = b.height + _xaxis.lineCapY1 + _xaxis.lineCapY2;
+			_xaxis.gridLines.mask = _xGridClip;
+			
+			o = t.$(_yGridClip);
+			o.x = b.x - _yaxis.lineCapX1;
+			o.y = b.y;
+			o.w = b.width + _yaxis.lineCapX1 + _yaxis.lineCapX2;
+			o.h = b.height + 1;
+			_yaxis.gridLines.mask = _yGridClip;
+			
+            return trans;
+        }
+		
+	} // end of class CartesianAxes
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/Axes.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/Axes.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/axis/Axes.as	(revision 15)
@@ -0,0 +1,42 @@
+package gssim.gssimstudio.editor.flare.vis.axis
+{
+	import flash.display.Sprite;
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Base class for representing metric data axes.
+	 */
+	public class Axes extends Sprite
+	{
+		/** The visualization the axes correspond to. */
+		protected var _vis:Visualization;
+		/** The layout bounds of the axes. */
+		protected var _bounds:Rectangle;
+		
+		/** The visualization the axes correspond to. */
+		public function get visualization():Visualization { return _vis; }
+		public function set visualization(v:Visualization):void { _vis = v; }
+
+		/** The layout bounds of the axes. If this value is not directly set,
+		 *  the layout bounds of the visualization are provided. */
+		public function get layoutBounds():Rectangle {
+			if (_bounds != null) return _bounds;
+			if (_vis != null) return _vis.bounds;
+			return null;
+		}
+		public function set layoutBounds(b:Rectangle):void { _bounds = b; }
+
+		/**
+		 * Update these axes, performing filtering and layout as needed.
+		 * @param trans a Transitioner for collecting value updates
+		 * @return the input transitioner
+		 */		
+		public function update(trans:Transitioner=null):Transitioner
+		{
+			return trans;
+		}
+		
+	} // end of class Axes
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/SelectionEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/SelectionEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/SelectionEvent.as	(revision 15)
@@ -0,0 +1,61 @@
+package gssim.gssimstudio.editor.flare.vis.events
+{
+	import flash.display.DisplayObject;
+	import flash.events.Event;
+	import flash.events.MouseEvent;
+
+	/**
+	 * Event fired in response to interactive selection events. 
+	 */
+	public class SelectionEvent extends DataEvent
+	{
+		/** A selection event. */
+		public static const SELECT:String   = "select";
+		/** A deselection event. */
+		public static const DESELECT:String = "deselect";
+		
+		/** Indicates whether the Alt key is active (<code>true</code>)
+		 *  or inactive (<code>false</code>). */
+		public var altKey:Boolean;
+		/** Indicates whether the Control key is active (<code>true</code>)
+		 *  or inactive (<code>false</code>). On Macintosh computers, you must
+		 *  use this property to represent the Command key. */
+		public var ctrlKey:Boolean;
+		/** Indicates whether the Shift key is active (<code>true</code>)
+		 *  or inactive (<code>false</code>). */
+		public var shiftKey:Boolean;
+		
+		/** The event that triggered this event, if any. */
+		public function get cause():MouseEvent { return _cause; }
+		private var _cause:MouseEvent;
+
+		/**
+		 * Creates a new SelectionEvent.
+		 * @param type the event type (SELECT or DESELECT)
+		 * @param item the display object(s) that were selected or deselected
+		 * @param e (optional) the MouseEvent that triggered the selection
+		 */
+		public function SelectionEvent(type:String, items:*, e:MouseEvent=null)
+		{
+			super(type, items);
+			if (e != null) {
+				_cause = e;
+				altKey = e.altKey;
+				ctrlKey = e.ctrlKey;
+				shiftKey = e.shiftKey;
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Event
+		{
+			var se:SelectionEvent = new SelectionEvent(type,
+				_items?_items:_item, _cause);
+			se.altKey = altKey;
+			se.ctrlKey = ctrlKey;
+			se.shiftKey = shiftKey;
+			return se;
+		}
+		
+	} // end of class SelectionEvent
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/DataEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/DataEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/DataEvent.as	(revision 15)
@@ -0,0 +1,78 @@
+package gssim.gssimstudio.editor.flare.vis.events
+{
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.events.Event;
+	
+	/**
+	 * Event fired when a data collection is modified.
+	 */
+	public class DataEvent extends Event
+	{
+		/** A data added event. */
+		public static const ADD:String    = "add";
+		/** A data removed event. */
+		public static const REMOVE:String = "remove";
+		/** A data updated event. */
+		public static const UPDATE:String = "update";
+		
+		/** @private */
+		protected var _items:Array;
+		/** @private */
+		protected var _item:Object;
+		/** @private */
+		private var _list:DataList;
+		
+		/** The number of items in this data event. */
+		public function get length():int {
+			return _items ? _items.length : 1;
+		}
+		
+		/** The list of effected data items. */
+		public function get items():Array {
+			if (_items == null) _items = [_item];
+			return _items;
+		}
+		
+		/** The data list (if any) the items belong to. */
+		public function get list():DataList { return _list; }
+		
+		/** The first element in the event list as an Object. */
+		public function get object():Object { return _item; }
+		/** The first element in the event list as a DataSprite. */
+		public function get item():DataSprite { return _item as DataSprite; }
+		/** The first element in the event list as a NodeSprite. */
+		public function get node():NodeSprite { return _item as NodeSprite; }
+		/** The first element in the event list as an EdgeSprite. */
+		public function get edge():EdgeSprite { return _item as EdgeSprite; }
+		
+		/**
+		 * Creates a new DataEvent.
+		 * @param type the event type (ADD, REMOVE, or UPDATE)
+		 * @param items the DataSprite(s) that were added, removed, or updated
+		 * @param list (optional) the data list that was modified
+		 */
+		public function DataEvent(type:String, items:*, list:DataList=null)
+		{
+			super(type, false, true);
+			if (items is Array) {
+				_items = items;
+				_item = _items[0];
+			} else {
+				_items = null;
+				_item = items;
+			}
+			_list = list;
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Event
+		{
+			return new DataEvent(type, _items?_items:_item, _list);
+		}
+		
+	} // end of class DataEvent
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/TooltipEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/TooltipEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/TooltipEvent.as	(revision 15)
@@ -0,0 +1,55 @@
+package gssim.gssimstudio.editor.flare.vis.events
+{
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.display.DisplayObject;
+	import flash.events.Event;
+
+	/**
+	 * Event fired in response to tooltip show, hide, or update events.
+	 * @see flare.vis.controls.TooltipControl
+	 */
+	public class TooltipEvent extends Event
+	{
+		/** A tooltip show event. */
+		public static const SHOW:String = "show";
+		/** A tooltip hide event. */
+		public static const HIDE:String = "hide";
+		/** A tooltip update event. */
+		public static const UPDATE:String = "update";
+		
+		private var _object:DisplayObject;
+		private var _tooltip:DisplayObject;
+		
+		/** The displayed tooltip object. */
+		public function get tooltip():DisplayObject { return _tooltip; }
+		
+		/** The moused-over interface object. */
+		public function get object():DisplayObject { return _object; }
+		/** The moused-over interface object, cast to a NodeSprite. */
+		public function get node():NodeSprite { return _object as NodeSprite; }
+		/** The moused-over interface object, cast to an EdgeSprite. */
+		public function get edge():EdgeSprite { return _object as EdgeSprite; }
+		
+		/**
+		 * Creates a new TooltipEvent.
+		 * @param type the event type (SHOW,HIDE, or UPDATE)
+		 * @param item the DisplayObject that was moused over
+		 * @param tip the tooltip DisplayObject
+		 */
+		public function TooltipEvent(type:String, item:DisplayObject, tip:DisplayObject)
+		{
+			super(type);
+			_object = item;
+			_tooltip = tip;
+		}
+		
+		/** @inheritDoc */
+		public override function clone():Event
+		{
+			return new TooltipEvent(type, _object, _tooltip);
+		}
+		
+	} // end of class TooltipEvent
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/VisualizationEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/VisualizationEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/events/VisualizationEvent.as	(revision 15)
@@ -0,0 +1,39 @@
+package gssim.gssimstudio.editor.flare.vis.events
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	
+	import flash.events.Event;
+
+	/**
+	 * Event fired in response to visualization updates.
+	 */
+	public class VisualizationEvent extends Event
+	{
+		/** A visualization update event. */
+		public static const UPDATE:String = "update";
+		
+		private var _trans:Transitioner;
+		private var _params:Array;
+		
+		/** Transitioner used in the visualization update. */
+		public function get transitioner():Transitioner { return _trans; }
+		
+		/** Parameter provided to the visualization update. If not null,
+		 *  this string indicates the named operators that were run. */
+		public function get params():Array { return _params; }
+		
+		/**
+		 * Creates a new VisualizationEvent.
+		 * @param type the event type
+		 * @param trans the Transitioner used in the visualization update
+		 */		
+		public function VisualizationEvent(type:String,
+			trans:Transitioner=null, params:Array=null)
+		{
+			super(type);
+			_params = params;
+			_trans = trans==null ? Transitioner.DEFAULT : trans;
+		}
+		
+	} // end of class VisualizationEvent
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/Data.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/Data.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/Data.as	(revision 15)
@@ -0,0 +1,600 @@
+package gssim.gssimstudio.editor.flare.vis.data
+{
+	import gssim.gssimstudio.editor.flare.data.DataField;
+	import gssim.gssimstudio.editor.flare.data.DataSchema;
+	import gssim.gssimstudio.editor.flare.data.DataSet;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.Sort;
+	import gssim.gssimstudio.editor.flare.vis.events.DataEvent;
+	
+	import flash.events.EventDispatcher;
+	
+	[Event(name="add",    type="flare.vis.events.DataEvent")]
+	[Event(name="remove", type="flare.vis.events.DataEvent")]
+	
+	/**
+	 * Data structure for managing a collection of visual data objects. The
+	 * Data class manages both unstructured data and data organized in a
+	 * general graph (or network structure), maintaining collections of both
+	 * nodes and edges. Collections of data sprites are maintained by
+	 * <code>DataList</code> instances. The individual data lists provide
+	 * methods for accessing, manipulating, sorting, and generating statistics
+	 * about the visual data objects.
+	 * 
+	 * <p>In addition to the required <code>nodes</code> and <code>edges</code>
+	 * lists, clients can add new custom lists (for example, to manage a
+	 * selected subset of the data) by using the <code>addGroup</code> method
+	 * and then accessing the list with the <code>group</code> method.
+	 * Individual data groups can be directly processed by many of the
+	 * visualization operators in the <code>flare.vis.operator</code> package.
+	 * </p>
+	 * 
+	 * <p>While Data objects maintain a collection of visual DataSprites,
+	 * they are not themselves visual object containers. Instead a Data
+	 * instance is used as input to a <code>Visualization</code> that
+	 * is responsible for processing the DataSprite instances and adding
+	 * them to the Flash display list.</p>
+	 * 
+	 * <p>The data class also manages the automatic generation of spanning
+	 * trees over a graph when needed for tree-based operations (such as tree
+	 * layout algorithms). This implemented by a
+	 * <code>flare.analytics.graph.SpanningTree</code> operator which can be
+	 * parameterized using the <code>treePolicy</code>,
+	 * <code>treeEdgeWeight</code>, and <code>root</code> properties of this
+	 * class. Alternatively, clients can create their own spanning trees as
+	 * a <code>Tree</code instance and set this as the spanning tree.</p>
+	 * 
+	 * @see flare.vis.data.DataList
+	 * @see flare.analytics.graph.SpanningTree
+	 */
+	public class Data extends EventDispatcher
+	{
+		/** Constant indicating the nodes in a Data object. */
+		public static const NODES:String = "nodes";
+		/** Constant indicating the edges in a Data object. */
+		public static const EDGES:String = "edges";
+		
+		/** Internal list of NodeSprites. */
+		protected var _nodes:DataList = new DataList(NODES);
+		/** Internal list of EdgeSprites. */
+		protected var _edges:DataList = new DataList(EDGES);
+		/** Internal set of data groups. */
+		protected var _groups:Object;
+		
+		/** The total number of items (nodes and edges) in the data. */
+		public function get length():int { return _nodes.length + _edges.length; }
+		
+		/** The collection of NodeSprites. */
+		public function get nodes():DataList { return _nodes; }
+		/** The collection of EdgeSprites. */
+		public function get edges():DataList { return _edges; }
+		
+		/** The default directedness of new edges. */
+		public var directedEdges:Boolean;
+		
+		
+		// -- Methods ---------------------------------------------------------
+
+		/**
+		 * Creates a new Data instance.
+		 * @param directedEdges the default directedness of new edges
+		 */
+		public function Data(directedEdges:Boolean=false) {
+			this.directedEdges = directedEdges;
+			_groups = { nodes: _nodes, edges: _edges };
+			
+			// add listeners to enforce type and connectivity constraints
+			_nodes.addEventListener(DataEvent.ADD, onAddNode);
+			_nodes.addEventListener(DataEvent.REMOVE, onRemoveNode);
+			_edges.addEventListener(DataEvent.ADD, onAddEdge);
+			_edges.addEventListener(DataEvent.REMOVE, onRemoveEdge);
+		}
+		
+		/**
+		 * Creates a new Data instance from an array of tuples. The object in
+		 * the array will become the data objects for NodeSprites.
+		 * @param a an Array of data objects
+		 * @return a new Data instance, with NodeSprites populated with the
+		 *  input data.
+		 */
+		public static function fromArray(a:Array):Data {
+			var d:Data = new Data();
+			for each (var tuple:Object in a) {
+				d.addNode(tuple);
+			}
+			return d;
+		}
+		
+		/**
+		 * Creates a new Data instance from a data set.
+		 * @param ds a DataSet to visualize. For example, this data set may be
+		 *  loaded using a data converter in the flare.data library.
+		 * @return a new Data instance, with NodeSprites and EdgeSprites
+		 *  populated with the input data.
+		 */
+		public static function fromDataSet(ds:DataSet):Data {			
+			var d:Data = new Data(), i:int;
+			var schema:DataSchema, f:DataField;
+			
+			// copy node data defaults
+			if ((schema = ds.nodes.schema)) {
+				for (i=0; i<schema.numFields; ++i) {
+					f = schema.getFieldAt(i);
+					if (f.defaultValue)
+						d.nodes.setDefault("data."+f.name, f.defaultValue);
+				}
+			}
+			// add node data
+			for each (var tuple:Object in ds.nodes.data) {
+				d.addNode(tuple);
+			}
+			// exit if there is no edge data
+			if (!ds.edges) return d;
+				
+			var nodes:DataList = d.nodes, map:Object = {};
+			var id:String = "id"; // TODO: generalize these fields?
+			var src:String = "source";
+			var trg:String = "target";
+			var dir:String = "directed";
+			
+			// build node map
+			for (i=0; i<nodes.length; ++i) {
+				map[nodes[i].data[id]] = nodes[i];
+			}
+			
+			// copy edge data defaults
+			if ((schema = ds.edges.schema)) {
+				for (i=0; i<schema.numFields; ++i) {
+					f = schema.getFieldAt(i);
+					if (f.defaultValue)
+						d.edges.setDefault("data."+f.name, f.defaultValue);
+				}
+				if ((f = schema.getFieldByName(dir))) {
+					d.directedEdges = Boolean(f.defaultValue);
+				}
+			}
+			// add edge data
+			for each (tuple in ds.edges.data) {
+				var n1:NodeSprite = map[tuple[src]];
+				if (!n1) throw new Error("Missing node id="+tuple[src]);
+				var n2:NodeSprite = map[tuple[trg]];
+				if (!n2) throw new Error("Missing node id="+tuple[trg]);
+				d.addEdgeFor(n1, n2, tuple[dir], tuple);
+			}
+			
+			return d;
+		}		
+		
+		// -- Group Management ---------------------------------
+		
+		/**
+		 * Adds a new data group. If a group of the same name already exists,
+		 * it will be replaced, except for the groups "nodes" and "edges",
+		 * which can not be replaced. 
+		 * @param name the name of the group to add
+		 * @param group the data list to add, if null a new,
+		 *  empty <code>DataList</code> instance will be created.
+		 * @return the added data group
+		 */
+		public function addGroup(name:String, group:DataList=null):DataList
+		{
+			if (name=="nodes" || name=="edges") {
+				throw new ArgumentError("Illegal group name. "
+					+ "\"nodes\" and \"edges\" are reserved names.");
+			}
+			if (group==null) group = new DataList(name);
+			_groups[name] = group;
+			return group;
+		}
+		
+		/**
+		 * Removes a data group. An error will be thrown if the caller
+		 * attempts to remove the groups "nodes" or "edges". 
+		 * @param name the name of the group to remove
+		 * @return the removed data group
+		 */
+		public function removeGroup(name:String):DataList
+		{
+			if (name=="nodes" || name=="edges") {
+				throw new ArgumentError("Illegal group name. "
+					+ "\"nodes\" and \"edges\" are reserved names.");
+			}
+			var group:DataList = _groups[name];
+			if (group) delete _groups[name];
+			return group;
+		}
+		
+		/**
+		 * Retrieves the data group with the given name. 
+		 * @param name the name of the group
+		 * @return the data group
+		 */
+		public function group(name:String):DataList
+		{
+			return _groups[name] as DataList;
+		}
+		
+		// -- Containment --------------------------------------
+		
+		/**
+		 * Indicates if this Data object contains the input DataSprite.
+		 * @param d the DataSprite to check for containment
+		 * @return true if the sprite is in this data collection, false
+		 *  otherwise.
+		 */
+		public function contains(d:DataSprite):Boolean
+		{
+			return (_nodes.contains(d) || _edges.contains(d));
+		}
+		
+		// -- Add ----------------------------------------------
+		
+		/**
+		 * Adds a node to this data collection.
+		 * @param d either a data tuple or NodeSprite object. If the input is
+		 *  a non-null data tuple, this will become the new node's
+		 *  <code>data</code> property. If the input is a NodeSprite, it will
+		 *  be directly added to the collection.
+		 * @return the newly added NodeSprite
+		 */
+		public function addNode(d:Object=null):NodeSprite
+		{
+			var ns:NodeSprite = NodeSprite(d is NodeSprite ? d : newNode(d));
+			_nodes.add(ns);
+			return ns;
+		}
+		
+		/**
+		 * Add an edge to this data set. The input must be of type EdgeSprite,
+		 * and must have both source and target nodes that are already in
+		 * this data set. If any of these conditions are not met, this method
+		 * will return null. Note that no exception will be thrown on failures.
+		 * @param e the EdgeSprite to add
+		 * @return the newly added EdgeSprite
+		 */
+		public function addEdge(e:EdgeSprite):EdgeSprite
+		{
+			return EdgeSprite(_edges.add(e));
+		}
+		
+		/**
+		 * Generates edges for this data collection that connect the nodes
+		 * according to the input properties. The nodes are sorted by the
+		 * sort argument and grouped by the group-by argument. All nodes
+		 * with the same group are sequentially connected to each other in
+		 * sorted order by new edges. This method is useful for generating
+		 * line charts from a plot of nodes.
+		 * <p>If an edge already exists between nodes, by default this method
+		 * will not add a new edge. Use the <code>ignoreExistingEdges</code>
+		 * argument to change this behavior. </p>
+		 * 
+		 * @param sortBy the criteria for sorting the nodes, using the format
+		 *  of <code>flare.util.Sort</code>. The input can either be a string
+		 *  with a single property name, or an array of property names.  Items
+		 *  are sorted in ascending order by default, prefix a property name
+		 *  with a "-" (minus) character to sort in descending order.
+		 * @param groupBy the criteria for grouping the nodes, using the format
+		 *  of <code>flare.util.Sort</code>. The input can either be a string
+		 *  with a single property name, or an array of property names. Items
+		 *  are sorted in ascending order by default, prefix a property name
+		 *  with a "-" (minus) character to sort in descending order.
+		 * @param ignoreExistingEdges if false (the default), this method will
+		 *  not create a new edge if one already exists between two nodes. If
+		 *  true, new edges will be created regardless.
+		 */
+		public function createEdges(sortBy:*=null, groupBy:*=null,
+			ignoreExistingEdges:Boolean=false):void
+		{
+			// create arrays and sort criteria
+			var a:Array = Arrays.copy(_nodes.list);
+			var g:Array = groupBy ? 
+				(groupBy is Array ? groupBy as Array : [groupBy]) : [];
+			var len:int = g.length;
+			if (sortBy is Array) {
+				var s:Array = sortBy as Array;
+				for (var i:uint=0; i<s.length; ++i)
+					g.push(s[i]);
+			} else {
+				g.push(sortBy);
+			}
+			
+			// sort to group by, then ordering
+			a.sort(Sort.$(g));
+			
+			// get property instances for value operations
+			var p:Array = new Array();
+			for (i=0; i<len; ++i) {
+				if (g[i] is String)
+					p.push(Property.$(g[i]));
+			}
+			var f:Property = p[p.length-1];
+			
+			// connect all items who match on the last group by field
+			for (i=1; i<a.length; ++i) {
+				if (!f || f.getValue(a[i-1]) == f.getValue(a[i])) {
+					if (!ignoreExistingEdges && a[i].isConnected(a[i-1]))
+						continue;
+					var e:EdgeSprite = addEdgeFor(a[i-1], a[i], directedEdges);
+					// add data values from nodes
+					for (var j:uint=0; j<p.length; ++j) {
+						p[j].setValue(e, p[j].getValue(a[i]));
+					}
+				}
+			}
+		}
+		
+		/**
+		 * Creates a new edge between the given nodes and adds it to the
+		 * data collection.
+		 * @param source the source node (must already be in this data set)
+		 * @param target the target node (must already be in this data set)
+		 * @param directed indicates the directedness of the edge (null to
+		 *  use this Data's default, true for directed, false for undirected)
+		 * @param data a data tuple containing data values for the edge
+		 *  instance. If non-null, this will become the EdgeSprite's
+		 *  <code>data</code> property.
+		 * @return the newly added EdgeSprite
+ 		 */
+		public function addEdgeFor(source:NodeSprite, target:NodeSprite,
+			directed:Object=null, data:Object=null):EdgeSprite
+		{
+			if (!_nodes.contains(source) || !_nodes.contains(target)) {
+				return null;
+			}
+			var d:Boolean = directed==null ? directedEdges : Boolean(directed);
+			var e:EdgeSprite = newEdge(source, target, d, data);
+			if (data != null) e.data = data;
+			source.addOutEdge(e);
+			target.addInEdge(e);
+			return addEdge(e);
+		}
+		
+		/**
+		 * Internal function for creating a new node. Creates a NodeSprite,
+		 * sets its data property, and applies default values.
+		 * @param data the new node's data property
+		 * @return the newly created node
+		 */
+		protected function newNode(data:Object):NodeSprite
+		{
+			var ns:NodeSprite = new NodeSprite();
+			_nodes.applyDefaults(ns);
+			if (data != null) { ns.data = data; }
+			return ns;
+		}
+		
+		/**
+		 * Internal function for creating a new edge. Creates an EdgeSprite,
+		 * sets its data property, and applies default values.
+		 * @param s the source node
+		 * @param t the target node
+		 * @param d the edge's directedness
+		 * @param data the new edge's data property
+		 * @return the newly created node
+		 */		
+		protected function newEdge(s:NodeSprite, t:NodeSprite,
+								   d:Boolean, data:Object):EdgeSprite
+		{
+			var es:EdgeSprite = new EdgeSprite(s,t,d);
+			_edges.applyDefaults(es);
+			if (data != null) { es.data = data; }
+			return es;
+		}
+		
+		// -- Remove -------------------------------------------
+		
+		/**
+		 * Clears this data set, removing all nodes and edges.
+		 */
+		public function clear():void
+		{
+			_edges.clear();
+			_nodes.clear();
+			for (var name:String in _groups) {
+				_groups[name].clear();
+			}
+		}
+		
+		/**
+		 * Removes a DataSprite (node or edge) from this data collection.
+		 * @param d the DataSprite to remove
+		 * @return true if removed successfully, false if not found
+		 */
+		public function remove(d:DataSprite):Boolean
+		{
+			if (d is NodeSprite) return removeNode(d as NodeSprite);
+			if (d is EdgeSprite) return removeEdge(d as EdgeSprite);
+			return false;
+		}
+				
+		/**
+		 * Removes a node from this data set. All edges incident on this
+		 * node will also be removed. If the node is not found in this
+		 * data set, the method returns null.
+		 * @param n the node to remove
+		 * @returns true if sucessfully removed, false if not found in the data
+		 */
+		public function removeNode(n:NodeSprite):Boolean
+		{
+			return _nodes.remove(n);
+		}
+		
+		/**
+		 * Removes an edge from this data set. The nodes connected to
+		 * this edge will have the edge removed from their edge lists.
+		 * @param e the edge to remove
+		 * @returns true if sucessfully removed, false if not found in the data
+		 */
+		public function removeEdge(e:EdgeSprite):Boolean
+		{
+			return _edges.remove(e);
+		}
+				
+		// -- Events -------------------------------------------
+		
+		/** @private */
+		protected function onAddNode(evt:DataEvent):void
+		{
+			for each (var d:DataSprite in evt.items) {
+				var n:NodeSprite = d as NodeSprite;
+				if (!n) {
+					evt.preventDefault();
+					return;
+				}
+			}
+			fireEvent(evt);
+		}
+		
+		/** @private */
+		protected function onRemoveNode(evt:DataEvent):void
+		{
+			for each (var n:NodeSprite in evt.items) {
+				for (var i:uint=n.outDegree; --i>=0;)
+					removeEdge(n.getOutEdge(i));
+				for (i=n.inDegree; --i>=0;)
+					removeEdge(n.getInEdge(i));
+			}
+			fireEvent(evt);
+		}
+		
+		/** @private */
+		protected function onAddEdge(evt:DataEvent):void
+		{
+			for each (var d:DataSprite in evt.items) {
+				var e:EdgeSprite = d as EdgeSprite;
+				if (!(e && _nodes.contains(e.source)
+					&& _nodes.contains(e.target)))
+				{
+					evt.preventDefault();
+					return;
+				}
+			}
+			fireEvent(evt);
+		}
+		
+		/** @private */
+		protected function onRemoveEdge(evt:DataEvent):void
+		{
+			for each (var e:EdgeSprite in evt.items) {
+				e.source.removeOutEdge(e);
+				e.target.removeInEdge(e);
+			}
+			fireEvent(evt);
+		}
+		
+		/** @private */
+		protected function fireEvent(evt:DataEvent):void
+		{			
+			// reset the spanning tree on adds and removals
+			if (evt.type != DataEvent.UPDATE)
+				_tree = null;
+			
+			// fire event, if anyone is listening
+			if (hasEventListener(evt.type)) {
+				dispatchEvent(evt);
+			}
+		}
+		
+		// -- Visitors -----------------------------------------
+		
+		/**
+		 * Visit items, invoking a function on all visited elements.
+		 * @param v the function to invoke on each element. If the function
+		 *  return true, the visitation is ended with an early exit
+		 * @param group the data group to visit (e.g., NODES or EDGES). If this
+		 *  value is null, both nodes and edges will be visited.
+		 * @param filter an optional predicate function indicating which
+		 *  elements should be visited. Only items for which this function
+		 *  returns true will be visited.
+  		 * @param reverse an optional parameter indicating if the visitation
+		 *  traversal should be done in reverse (the default is false).
+		 * @return true if the visitation was interrupted with an early exit
+		 */
+		public function visit(v:Function, group:String=null,
+			filter:*=null, reverse:Boolean=false):Boolean
+		{
+			if (group == null) {
+				if (_edges.length > 0 && _edges.visit(v, filter, reverse))
+					return true;
+				if (_nodes.length > 0 && _nodes.visit(v, filter, reverse))
+					return true;
+			} else {
+				var list:DataList = _groups[group];
+				if (list.length > 0 && list.visit(v, filter, reverse))
+					return true;
+			}
+			return false;
+		}
+		
+		
+		// -- Spanning Tree ---------------------------------------------------
+		
+		/** The spanning tree constructor class. */
+		protected var _span:TreeBuilder = new TreeBuilder();
+		/** The root node of the spanning tree. */
+		protected var _root:NodeSprite = null;
+		/** The the spanning tree. */
+		protected var _tree:Tree = null;
+		
+		/** The spanning tree creation policy. 
+		 *  @see flare.analytics.graph.SpanningTree */
+		public function get treePolicy():String { return _span.policy; }
+		public function set treePolicy(p:String):void {
+			if (_span.policy != p) {
+				_span.policy = p;
+				_tree = null;
+			}
+		}
+		
+		/** The edge weight function for computing a minimum spanning tree.
+		 *  This function will only have an effect if the
+		 *  <code>treePolicy</code> is
+		 *  <code>SpanningTree.MINIMUM_SPAN</code> */
+		public function get treeEdgeWeight():Function {
+			return (_span ? _span.edgeWeight : null);
+		}
+		public function set treeEdgeWeight(w:*):void {
+			_span.edgeWeight = w;
+		}
+		
+		/** The root node of the spanning tree. */
+		public function get root():NodeSprite { return _root; }
+		public function set root(n:NodeSprite):void {
+			if (n != null && !_nodes.contains(n))
+				throw new ArgumentError("Spanning tree root must be within the graph.");
+			if (_root != n) {
+				_tree = null;
+				_span.root = (_root = n);
+			}
+		}
+		
+		/**
+		 * A spanning tree for this graph. The spanning tree generated is
+		 * determined by the <code>root</code>, <code>treePolicy</code>,
+		 * and <code>treeEdgeWeight</code> properties. By default, the tree
+		 * is built using a breadth-first spanning tree using the first node
+		 * in the graph as the root.
+		 */
+		public function get tree():Tree
+		{
+			if (_tree == null) { // build tree if necessary
+				if (_root == null) _span.root = _nodes[0];
+				_span.calculate(this, _span.root);
+				_tree = _span.tree;
+			}
+			return _tree;	
+		}
+		public function set tree(t:Tree):void
+		{
+			if (t==null) { _tree = null; return; }
+			
+			var ok:Boolean;
+			ok = t.root.visitTreeDepthFirst(function(n:NodeSprite):Boolean {
+				return _nodes.contains(n);
+			});
+			if (ok) _tree = t;
+		}
+
+	} // end of class Data
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/EdgeSprite.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/EdgeSprite.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/EdgeSprite.as	(revision 15)
@@ -0,0 +1,103 @@
+package gssim.gssimstudio.editor.flare.vis.data
+{
+	import gssim.gssimstudio.editor.flare.vis.data.render.ArrowType;
+	import gssim.gssimstudio.editor.flare.vis.data.render.EdgeRenderer;
+	
+	/**
+	 * Visually represents a connection between two data elements. Examples
+	 * include an edge in a graph structure or a line between points in a line
+	 * chart. EdgeSprites maintain <code>source</code> and <code>target</code>
+	 * properties for accessing the NodeSprites connected by this edge. By
+	 * default, EdgeSprites are drawn using an <code>EdgeRenderer</code>.
+	 * EdgeSprites are typically managed by a <code>Data</code> object.
+	 */
+	public class EdgeSprite extends DataSprite
+	{		
+		// -- Properties ------------------------------------------------------
+		
+		/** The x-coordinate for the first end point of this edge. */
+		public var x1:Number;
+		/** The y-coordinate for the first end point of this edge. */
+		public var y1:Number;
+		/** The x-coordinate for the second end point of this edge. */
+		public var x2:Number;
+		/** The y-coordinate for the second end point of this edge. */
+		public var y2:Number;
+		
+		/** The first, or source, node upon which this edge is incident. */
+		public var source:NodeSprite;
+		/** The second, or target, node upon which this edge is incident. */
+		public var target:NodeSprite;
+		
+		/** Flag indicating if this edge is directed (true) or undirected
+		 *  (false). */
+		public var directed:Boolean = false;
+		
+		/** The type of arrow to be used on the edge. Default is Arrows.NONE */
+		public var arrowType:String = ArrowType.NONE;
+		/** The width of the arrow head. The default is -1, in which case the
+		 *  width is automatically determined based on the arrow height or
+		 *  the line width. */
+		public var arrowWidth:Number = -1;
+		/** The height of the arrow head. The default is -1, in which case the
+		 *  height is automatically determined based on the arrow width or
+		 *  the line width. */
+		public var arrowHeight:Number = -1;
+		
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates a new EdgeSprite.
+		 * @param source the source node
+		 * @param target the target node
+		 * @param directed true for a directed edge, false for undirected
+		 */		
+		public function EdgeSprite(source:NodeSprite=null,
+			target:NodeSprite=null, directed:Boolean=false)
+		{
+			this.source = source;
+			this.target = target;
+			this.directed = directed;
+			_lineColor = 0xffcccccc;
+			_renderer = EdgeRenderer.instance;
+		}
+		
+		/**
+		 * Given a node upon which this edge is incident, return the other
+		 * node connected by this edge.
+		 * @param n a node upon which this edge is incident
+		 * @return the other node
+		 */		
+		public function other(n:NodeSprite):NodeSprite
+		{
+			if (n == source) return target;
+			if (n == target) return source;
+			else return null;	
+		}
+		
+		/**
+		 * Clears the edge, removing references to the edge's nodes.
+		 */		
+		public function clear():void
+		{
+			source = null;
+			target = null;
+		}
+		
+		/** @inheritDoc */
+		public override function render():void
+		{
+			if (source != null) {
+				x1 = source.x;
+				y1 = source.y;
+			}
+			if (target != null) {
+				x2 = target.x;
+				y2 = target.y;
+			}
+			super.render();
+		}
+		
+	} // end of class EdgeSprite
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/NodeSprite.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/NodeSprite.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/NodeSprite.as	(revision 15)
@@ -0,0 +1,560 @@
+package gssim.gssimstudio.editor.flare.vis.data
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Filter;
+	import gssim.gssimstudio.editor.flare.util.IEvaluable;
+	import gssim.gssimstudio.editor.flare.util.Sort;
+	
+	/**
+	 * Visually represents a data element, such as a data tuple or graph node.
+	 * By default, NodeSprites are drawn using a <codeShapeRenderer<code>.
+	 * NodeSprites are typically managed by a <code>Data</code> object.
+	 * 
+	 * <p>NodeSprites can separately maintain adjacency lists for both a
+	 * general graph structure (managing lists for inlinks and outlinks) and a
+	 * tree structure (managing a list for child links and a parent pointer).
+	 * The graph and tree lists are maintained completely separately to
+	 * maximize flexibility. While the the tree lists are often used to record
+	 * a spanning tree of the general network structure, they can also be used
+	 * to represent a hierarchy completely distinct from a co-existing graph
+	 * structure. Take this into account when iterating over the edges incident
+	 * on this node.</p>
+	 */
+	public class NodeSprite extends DataSprite
+	{
+		/** Flag indicating inlinks, edges that point to this node. */
+		public static const IN_LINKS:uint    = 1;
+		/** Flag indicating outlinks, edges that point away from node. */
+		public static const OUT_LINKS:uint   = 2;
+		/** Flag indicating both inlinks and outlinks. */
+		public static const GRAPH_LINKS:uint = 3;  // IN_LINKS | OUT_LINKS
+		/** Flag indicating child links in a tree structure. */
+		public static const CHILD_LINKS:uint = 4;
+		/** Flag indicating the link to a parent in a tree structure. */
+		public static const PARENT_LINK:uint = 8;
+		/** Flag indicating both child and parent links. */
+		public static const TREE_LINKS:uint  = 12; // CHILD_LINKS | PARENT_LINK
+		/** Flag indicating all links, including graph and tree links. */
+		public static const ALL_LINKS:uint   = 15; // GRAPH_LINKS | TREE_LINKS
+		/** Flag indicating that a traversal should be performed in reverse. */
+		public static const REVERSE:uint     = 16;
+		
+		// -- Properties ------------------------------------------------------
+		
+		private var _parentEdge:EdgeSprite;
+		private var _idx:int = -1; // node index in parent's array
+		private var _childEdges:/*EdgeSprite*/Array;
+		private var _inEdges:/*EdgeSprite*/Array;
+		private var _outEdges:/*EdgeSprite*/Array;
+		private var _expanded:Boolean = true;
+		
+		/** Flag indicating if this node is currently expanded. This flag can
+		 *  be used by layout routines to expand/collapse connections. */
+		public function get expanded():Boolean { return _expanded; }
+		public function set expanded(b:Boolean):void { _expanded = b; }
+		
+		/** The edge connecting this node to its parent in a tree structure. */
+		public function get parentEdge():EdgeSprite { return _parentEdge; }
+		public function set parentEdge(e:EdgeSprite):void { _parentEdge = e; }
+		
+		/** The index of this node in its tree parent's child links list. */
+		public function get parentIndex():int { return _idx; }
+		public function set parentIndex(i:int):void { _idx = i; }
+
+		// -- Node Degree Properties ------------------------------------------
+
+		/** The number of child links. */
+		public function get childDegree():uint { return _childEdges==null ? 0 : _childEdges.length; }
+		/** The number of inlinks and outlinks. */
+		public function get degree():uint { return inDegree + outDegree; }
+		/** The number of inlinks. */
+		public function get inDegree():uint { return _inEdges==null ? 0 : _inEdges.length; }
+		/** The number of outlinks. */
+		public function get outDegree():uint { return _outEdges==null ? 0 : _outEdges.length; }
+
+		/** The depth of this node in the tree structure. A value of zero
+		 *  indicates that this is a root node or that there is no tree. */
+		public function get depth():uint {
+			for (var d:uint=0, p:NodeSprite=parentNode; p!=null; p=p.parentNode, d++) null;
+			return d;
+		}
+
+		// -- Node Access Properties ---------------------------
+
+		/** The parent of this node in the tree structure. */
+		public function get parentNode():NodeSprite
+		{
+			return _parentEdge == null ? null : _parentEdge.other(this);
+		}
+		
+		/** The first child of this node in the tree structure. */
+		public function get firstChildNode():NodeSprite
+		{
+			return childDegree > 0 ? _childEdges[0].other(this) : null;
+		}
+		
+		/** The last child of this node in the tree structure. */
+		public function get lastChildNode():NodeSprite
+		{
+			var len:uint = childDegree;
+			return len > 0 ? _childEdges[len-1].other(this) : null;
+		}
+		
+		/** The next sibling of this node in the tree structure. */
+		public function get nextNode():NodeSprite
+		{
+			var p:NodeSprite = parentNode, i:int = _idx+1;
+			if (p == null || i >= p.childDegree) return null;
+			return parentNode.getChildNode(i);
+		}
+		
+		/** The previous sibling of this node in the tree structure. */
+		public function get prevNode():NodeSprite
+		{
+			var p:NodeSprite = parentNode, i:int = _idx-1;
+			if (p == null || i < 0) return null;
+			return parentNode.getChildNode(i);
+		}
+		
+		// -- Position Overrides -------------------------------
+
+		/** @inheritDoc */
+		public override function set x(v:Number):void
+		{
+			if (x!=v) dirtyEdges();
+			super.x = v;
+		}
+		/** @inheritDoc */
+		public override function set y(v:Number):void
+		{
+			if (y!=v) dirtyEdges();
+			super.y = v;
+		}
+		/** @inheritDoc */
+		public override function set radius(r:Number):void
+		{
+			if (_radius!=r) dirtyEdges();
+			super.radius = r;
+		}
+		/** @inheritDoc */
+		public override function set angle(a:Number):void
+		{
+			if (_angle!=a) dirtyEdges();
+			super.angle = a;
+		}
+		
+		// -- Methods ---------------------------------------------------------
+
+		/** Mark all incident edges as dirty. */
+		private function dirtyEdges():void
+		{
+			var e:EdgeSprite;
+			if (_parentEdge) _parentEdge.dirty();
+			if (_childEdges) for each (e in _childEdges) { e.dirty(); }
+			if (_outEdges)   for each (e in _outEdges)   { e.dirty(); }
+			if (_inEdges)    for each (e in _inEdges)    { e.dirty(); }
+		}
+		
+		// -- Test Methods -------------------------------------
+		
+		/**
+		 * Indicates if the input node is connected to this node by an edge.
+		 * @param n the node to check for connection
+		 * @param opt flag indicating which links to check
+		 * @return true if connected, false otherwise
+		 */		
+		public function isConnected(n:NodeSprite, opt:uint=ALL_LINKS):Boolean
+		{
+			return visitNodes(
+				function(d:NodeSprite):Boolean { return n==d; },
+				opt);
+		}
+
+		// -- Accessor Methods ---------------------------------
+		
+		/**
+		 * Gets the child edge at the specified position
+		 * @param i the position of the child edge
+		 * @return the child edge
+		 */		
+		public function getChildEdge(i:uint):EdgeSprite
+		{
+			return _childEdges[i];
+		}
+		
+		/**
+		 * Gets the child node at the specified position
+		 * @param i the position of the child node
+		 * @return the child node
+		 */
+		public function getChildNode(i:uint):NodeSprite
+		{
+			return _childEdges[i].other(this);
+		}
+		
+		/**
+		 * Gets the inlink edge at the specified position
+		 * @param i the position of the inlink edge
+		 * @return the inlink edge
+		 */
+		public function getInEdge(i:uint):EdgeSprite
+		{
+			return _inEdges[i];
+		}
+		
+		/**
+		 * Gets the inlink node at the specified position
+		 * @param i the position of the inlink node
+		 * @return the inlink node
+		 */
+		public function getInNode(i:uint):NodeSprite
+		{
+			return _inEdges[i].source;
+		}
+		
+		/**
+		 * Gets the outlink edge at the specified position
+		 * @param i the position of the outlink edge
+		 * @return the outlink edge
+		 */
+		public function getOutEdge(i:uint):EdgeSprite
+		{
+			return _outEdges[i];
+		}
+		
+		/**
+		 * Gets the outlink node at the specified position
+		 * @param i the position of the outlink node
+		 * @return the outlink node
+		 */
+		public function getOutNode(i:uint):NodeSprite
+		{
+			return _outEdges[i].target;
+		}
+		
+		// -- Mutator Methods ----------------------------------
+		
+		/**
+		 * Adds a child edge to this node.
+		 * @param e the edge to add to the child links list
+		 * @return the index of the added edge in the list
+		 */
+		public function addChildEdge(e:EdgeSprite):uint
+		{
+			if (_childEdges == null) _childEdges = new Array();
+			_childEdges.push(e);
+			return _childEdges.length - 1;
+		}
+		
+		/**
+		 * Adds an inlink edge to this node.
+		 * @param e the edge to add to the inlinks list
+		 * @return the index of the added edge in the list
+		 */
+		public function addInEdge(e:EdgeSprite):uint
+		{
+			if (_inEdges == null) _inEdges = new Array();
+			_inEdges.push(e);
+			return _inEdges.length - 1;
+		}
+		
+		/**
+		 * Adds an outlink edge to this node.
+		 * @param e the edge to add to the outlinks list
+		 * @return the index of the added edge in the list
+		 */
+		public function addOutEdge(e:EdgeSprite):uint
+		{
+			if (_outEdges == null) _outEdges = new Array();
+			_outEdges.push(e);
+			return _outEdges.length - 1;
+		}
+		
+		/**
+		 * Removes all edges incident on this node. Note that this method
+		 * does not update the edges themselves or the other nodes.
+		 */
+		public function removeAllEdges():void
+		{
+			removeEdges(ALL_LINKS);
+		}
+		
+		/**
+		 * Removes all edges of the indicated edge type. Note that this method
+		 * does not update the edges themselves or the other nodes.
+		 * @param type the type of edges to remove. For example, IN_LINKS,
+		 *  OUT_LINKS, TREE_LINKS, etc.
+		 */
+		public function removeEdges(type:int):void
+		{
+			var e:EdgeSprite;
+			if (type & PARENT_LINK && _parentEdge) {
+				_parentEdge = null;
+			}
+			if (type & CHILD_LINKS && _childEdges) {
+				while (_childEdges.length > 0) { e=_childEdges.pop(); }
+			}
+			if (type & OUT_LINKS && _outEdges) {
+				while (_outEdges.length > 0) { e=_outEdges.pop(); }
+			}
+			if (type & IN_LINKS && _inEdges) {
+				while (_inEdges.length > 0) { e=_inEdges.pop(); }	
+			}
+		}
+		
+		/**
+		 * Removes an edge from the child links list. Note that this method
+		 * does not update the edge itself or the other node.
+		 * @param e the edge to remove
+		 */
+		public function removeChildEdge(e:EdgeSprite):void
+		{
+			Arrays.remove(_childEdges, e);
+		}
+		
+		/**
+		 * Removes an edge from the inlinks list. Note that this method
+		 * does not update the edge itself or the other node.
+		 * @param e the edge to remove
+		 */
+		public function removeInEdge(e:EdgeSprite):void
+		{
+			Arrays.remove(_inEdges, e);
+		}
+		
+		/**
+		 * Removes an edge from the outlinks list. Note that this method
+		 * does not update the edge itself or the other node.
+		 * @param e the edge to remove
+		 */
+		public function removeOutEdge(e:EdgeSprite):void
+		{
+			Arrays.remove(_outEdges, e);
+		}
+		
+		// -- Visitor Methods --------------------------------------------------
+		
+		/**
+		 * Sorts the order of connected edges according to their properties.
+		 * Each type of edge (in, out, or child) is sorted separately.
+		 * @param opt flag indicating which set(s) of edges should be sorted
+		 * @param sort the sort arguments.
+		 * 	If a String is provided, the data will be sorted in ascending order
+		 *   according to the data field named by the string.
+		 *  If an Array is provided, the data will be sorted according to the
+		 *   fields in the array. In addition, field names can optionally
+		 *   be followed by a boolean value. If true, the data is sorted in
+		 *   ascending order (the default). If false, the data is sorted in
+		 *   descending order.
+		 */
+		public function sortEdgesBy(opt:uint=ALL_LINKS, ...sort):void
+		{
+			if (sort.length == 0) return;
+			if (sort[0] is Array) sort = sort[0];
+			
+			var s:Function = Sort.$(sort);
+			if (opt & IN_LINKS    && _inEdges    != null) _inEdges.sort(s);
+			if (opt & OUT_LINKS   && _outEdges   != null) _outEdges.sort(s);
+			if (opt & CHILD_LINKS && _childEdges != null) {
+				_childEdges.sort(s);
+				for (var i:uint=0; i<_childEdges.length; ++i)
+					_childEdges[i].other(this).parentIndex = i;
+			}
+		}
+		
+		/**
+		 * Visits this node's edges, invoking a function on each visited edge.
+		 * @param f the function to invoke on the edges. If the function
+		 *  returns true, the visitation is ended with an early exit.
+		 * @param opt flag indicating which sets of edges should be visited
+		 * @return true if the visitation was interrupted with an early exit
+		 */
+		public function visitEdges(f:Function, opt:uint=ALL_LINKS,
+			filter:*=null):Boolean
+		{
+			var ff:Function = Filter.$(filter);
+			var rev:Boolean = (opt & REVERSE) > 0;
+			if (opt & IN_LINKS && _inEdges != null) { 
+				if (visitEdgeHelper(f, _inEdges, rev, ff)) return true;
+			}
+			if (opt & OUT_LINKS && _outEdges != null) {
+				if (visitEdgeHelper(f, _outEdges, rev, ff)) return true;
+			}
+			if (opt & CHILD_LINKS && _childEdges != null) {
+				if (visitEdgeHelper(f, _childEdges, rev, ff)) return true;
+			}
+			if (opt & PARENT_LINK && _parentEdge != null) {
+				if ((ff==null || ff(_parentEdge)) && f(_parentEdge))
+					return true;
+			}
+			return false;
+		}
+		
+		private function visitEdgeHelper(f:Function, a:Array, r:Boolean,
+			ff:Function):Boolean
+		{
+			var i:uint, n:uint=a.length, v:*;
+			if (r) {
+				for (i=n; --i>=0;) {
+					if ((ff==null || ff(a[i])) && f(a[i]) as Boolean)
+						return true;
+				}
+			} else {
+				for (i=0; i<n; ++i) {
+					if ((ff==null || ff(a[i])) && f(a[i]) as Boolean)
+						return true;
+				}
+			}
+			return false;
+		}
+		
+		/**
+		 * Visits the nodes connected to this node by edges, invoking a
+		 * function on each visited node.
+		 * @param f the function to invoke on the nodes. If the function
+		 *  returns true, the visitation is ended with an early exit.
+		 * @param opt flag indicating which sets of edges should be traversed
+		 * @return true if the visitation was interrupted with an early exit
+		 */
+		public function visitNodes(f:Function, opt:uint=ALL_LINKS,
+			filter:*=null):Boolean
+		{
+			var ff:Function = Filter.$(filter);
+			var rev:Boolean = (opt & REVERSE) > 0;
+			if (opt & IN_LINKS && _inEdges != null) {
+				if (visitNodeHelper(f, _inEdges, rev, ff)) return true;
+			}
+			if (opt & OUT_LINKS && _outEdges != null) {
+				if (visitNodeHelper(f, _outEdges, rev, ff)) return true;
+			}
+			if (opt & CHILD_LINKS && _childEdges != null) {
+				if (visitNodeHelper(f, _childEdges, rev, ff)) return true;
+			}
+			if (opt & PARENT_LINK && _parentEdge != null) {
+				if ((ff==null||ff(_parentEdge)) && f(_parentEdge.other(this)))
+					return true;
+			}
+			return false;
+		}
+		
+		private function visitNodeHelper(f:Function, a:Array, r:Boolean,
+			ff:Function):Boolean
+		{
+			var i:uint, n:uint=a.length, u:NodeSprite;
+			if (r) {
+				for (i=n; --i>=0;) {
+					u = a[i].other(this);
+					if ((ff==null || ff(u)) && f(u) as Boolean)
+						return true;
+				}
+			} else {
+				for (i=0; i<n; ++i) {
+					u = a[i].other(this);
+					if ((ff==null || ff(u)) && f(u) as Boolean)
+						return true;
+				}
+			}
+			return false;
+		}
+		
+		/**
+		 * Visits the subtree rooted at this node using a depth first search,
+		 * invoking the input function on each visited node.
+		 * @param f the function to invoke on the nodes. If the function
+		 *  returns true, the visitation is ended with an early exit.
+		 * @param preorder if true, nodes are visited in a pre-order traversal;
+		 *  if false, they are visited in a post-order traversal
+		 * @return true if the visitation was interrupted with an early exit
+		 */
+		public function visitTreeDepthFirst(f:Function, preorder:Boolean=false):Boolean
+		{
+			if (preorder && (f(this) as Boolean)) return true;
+			for (var i:uint = 0; i<childDegree; ++i) {
+				if (getChildNode(i).visitTreeDepthFirst(f, preorder))
+					return true;
+			}
+			if (!preorder && (f(this) as Boolean)) return true;
+			return false;
+		}
+		
+		/**
+		 * Visits the subtree rooted at this node using a breadth first search,
+		 * invoking the input function on each visited node.
+		 * @param f the function to invoke on the nodes. If the function
+		 *  returns true, the visitation is ended with an early exit.
+		 * @return true if the visitation was interrupted with an early exit
+		 */
+		public function visitTreeBreadthFirst(f:Function):Boolean
+		{
+			var q:Array = new Array(), x:NodeSprite;
+			
+			q.push(this);
+			while (q.length > 0) {
+				if (f(x=q.shift()) as Boolean) return true;
+				for (var i:uint = 0; i<x.childDegree; ++i)
+					q.push(x.getChildNode(i));
+			}
+			return false;
+		}
+		
+		/**
+		 * Sets property values on edge sprites connected to this node.
+		 * @param vals an object containing the properties and values to set.
+		 * @param opt flag indicating which sets of edges should be traversed
+		 * @param trans a transitioner or time span for updating object values.
+		 *  If the input is a transitioner, it will be used to store the
+		 *  updated  values. If the input is a number, a new Transitioner with
+		 *  duration set to the input value will be used. The input is null by
+		 *  default, in which case object values are updated immediately.
+		 * @param filter an optional Boolean-valued filter function for
+		 * 	limiting which items are visited
+		 * @return the transitioner used to update the values
+		 */
+		public function setEdgeProperties(vals:Object, opt:uint=ALL_LINKS,
+			trans:*=null, filter:*=null):Transitioner
+		{
+			var t:Transitioner = Transitioner.instance(trans);
+			for (var name:String in vals) {
+				var val:* = vals[name];
+				var v:Function = val is Function ? val as Function
+					 : val is IEvaluable ? IEvaluable(val).eval : null;
+				
+				visitEdges(function(s:EdgeSprite):void {
+					t.setValue(s, name, (v!=null ? v(t.$(s)) : val));
+				}, opt, filter);
+			}
+			return t;
+		}
+		
+		/**
+		 * Sets property values on node sprites connected to this node.
+		 * @param vals an object containing the properties and values to set.
+		 * @param opt flag indicating which sets of nodes should be traversed
+		 * @param trans a transitioner or time span for updating object values.
+		 *  If the input is a transitioner, it will be used to store the
+		 *  updated  values. If the input is a number, a new Transitioner with
+		 *  duration set to the input value will be used. The input is null by
+		 *  default, in which case object values are updated immediately.
+		 * @param filter an optional Boolean-valued filter function for
+		 * 	limiting which items are visited
+		 * @return the transitioner used to update the values
+		 */
+		public function setNodeProperties(vals:Object, opt:uint=ALL_LINKS,
+			trans:*=null, filter:*=null):Transitioner
+		{
+			var t:Transitioner = Transitioner.instance(trans);
+			for (var name:String in vals) {
+				var val:* = vals[name];
+				var v:Function = val is Function ? val as Function
+					 : val is IEvaluable ? IEvaluable(val).eval : null;
+
+				visitNodes(function(n:NodeSprite):void {
+					t.setValue(n, name, (v!=null ? v(t.$(n)) : val));
+				}, opt, filter);
+			}
+			return t;
+		}
+		
+	} // end of class NodeSprite
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/ShapeRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/ShapeRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/ShapeRenderer.as	(revision 15)
@@ -0,0 +1,77 @@
+package gssim.gssimstudio.editor.flare.vis.data.render
+{
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	
+	import flash.display.Graphics;
+
+	/**
+	 * Renderer that draws shapes. The ShapeRender uses a ShapePalette instance
+	 * as needed to look up shape drawing routines based on the DataSprite
+	 * <code>shape</code> property.
+	 * @see flare.vis.palette.ShapePalette
+	 */
+	public class ShapeRenderer implements IRenderer
+	{
+		private static var _instance:ShapeRenderer = new ShapeRenderer();
+		/** Static ShapeRenderer instance. */
+		public static function get instance():ShapeRenderer { return _instance; }
+		
+		/** The default size value for drawn shapes. This value is multiplied
+		 *  by a DataSprite's size property to determine the final size. */
+		public var defaultSize:Number;
+		
+		/**
+		 * Creates a new ShapeRenderer 
+		 * @param defaultSize the default size (radius) for shapes
+		 */
+		public function ShapeRenderer(defaultSize:Number=6) {
+			this.defaultSize = defaultSize;
+		}
+		
+		/** @inheritDoc */
+		public function render(d:DataSprite):void
+		{
+			var lineAlpha:Number = d.lineAlpha;
+			var fillAlpha:Number = d.fillAlpha;
+			var size:Number = d.size * defaultSize;
+			
+			var g:Graphics = d.graphics;
+			g.clear();
+			if (fillAlpha > 0) g.beginFill(d.fillColor, fillAlpha);
+			if (lineAlpha > 0) g.lineStyle(d.lineWidth, d.lineColor, lineAlpha);
+			
+			switch (d.shape) {
+				case null:
+					break;
+				case Shapes.BLOCK:
+					g.drawRect(d.u-d.x, d.v-d.y, d.w, d.h);
+					break;
+				case Shapes.POLYGON:
+					if (d.points!=null)
+						Shapes.drawPolygon(g, d.points);
+					break;
+				case Shapes.POLYBLOB:
+					if (d.points!=null)
+						Shapes.drawCardinal(g, d.points,
+											d.points.length/2, 0.15, true);
+					break;
+				case Shapes.VERTICAL_BAR:
+					g.drawRect(-size/2, -d.h, size, d.h); 
+					break;
+				case Shapes.HORIZONTAL_BAR:
+					g.drawRect(-d.w, -size/2, d.w, size);
+					break;
+				case Shapes.WEDGE:
+					Shapes.drawWedge(g, d.origin.x-d.x, d.origin.y-d.y,
+									 d.h, d.v, d.u, d.u+d.w);
+					break;
+				default:
+					Shapes.getShape(d.shape)(g, size);
+			}
+			
+			if (fillAlpha > 0) g.endFill();
+		}
+		
+	} // end of class ShapeRenderer
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/EdgeRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/EdgeRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/EdgeRenderer.as	(revision 15)
@@ -0,0 +1,178 @@
+package gssim.gssimstudio.editor.flare.vis.data.render
+{
+	import gssim.gssimstudio.editor.flare.util.Geometry;
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.display.Graphics;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+
+	/**
+	 * Renderer that draws edges as lines. The EdgeRenderer supports straight
+	 * lines, poly lines, and curves as Bezier or cardinal splines. The type
+	 * of edge drawn is determined from an EdgeSprite's <code>shape</code>
+	 * property and control points found in the <code>points</code> property.
+	 * The line rendering properties are set by the <code>setLineStyle</code>
+	 * method, which can be overridden by subclasses. By default, the line
+	 * rendering settings are determined using default property values set
+	 * on this class (for example, the <code>scaleMode<code> and 
+	 * <code>caps</code> properties).
+	 */
+	public class EdgeRenderer implements IRenderer
+	{		
+		private static const ROOT3:Number = Math.sqrt(3);
+		
+		private static var _instance:EdgeRenderer = new EdgeRenderer();
+		/** Static EdgeRenderer instance. */
+		public static function get instance():EdgeRenderer { return _instance; }
+		
+		/** Pixel hinting flag for line rendering. */
+		public var pixelHinting:Boolean = false;
+		/** Scale mode for line rendering (normal by default). */
+		public var scaleMode:String = "normal";
+		/** The joint style for line rendering. */
+		public var joints:String = null;
+		/** The caps style for line rendering. */
+		public var caps:String = null;
+		/** The miter limit for line rendering. */
+		public var miterLimit:int = 3;
+		
+		// temporary variables
+		private var _p:Point = new Point(), _q:Point = new Point();
+		private var _pts:Array = new Array(20);
+		
+		/** @inheritDoc */
+		public function render(d:DataSprite):void
+		{
+			var e:EdgeSprite = d as EdgeSprite;
+			if (e == null) { return; } // TODO: throw exception?
+			var s:NodeSprite = e.source;
+			var t:NodeSprite = e.target;
+			var g:Graphics = e.graphics;
+			
+			var ctrls:Array = e.points as Array;
+			var x1:Number = e.x1, y1:Number = e.y1;
+			var x2:Number = e.x2, y2:Number = e.y2;
+			var xL:Number = ctrls==null ? x1 : ctrls[ctrls.length-2];
+			var yL:Number = ctrls==null ? y1 : ctrls[ctrls.length-1];
+			var dx:Number, dy:Number, dd:Number;
+
+			// modify end points as needed to accomodate arrow
+			if (e.arrowType != ArrowType.NONE)
+			{
+				// determine arrow head size
+				var ah:Number = e.arrowHeight, aw:Number = e.arrowWidth/2;
+				if (ah < 0 && aw < 0)
+					aw = 1.5 * e.lineWidth;
+				if (ah < 0) {
+					ah = ROOT3 * aw;
+				} else if (aw < 0) {
+					aw = ah / ROOT3;
+				}
+				
+				// get arrow tip point as intersection of edge with bounding box
+				if (t==null) {
+					_p.x = x2; _p.y = y2;
+				} else {
+					var r:Rectangle = t.getBounds(t.parent);
+					if (Geometry.intersectLineRect(xL,yL,x2,y2, r, _p,_q) <= 0)
+					{
+						_p.x = x2; _p.y = y2;
+					}
+				}
+				
+				// get unit vector along arrow line
+				dx = _p.x - xL; dy = _p.y - yL;
+				dd = Math.sqrt(dx*dx + dy*dy);
+				dx /= dd; dy /= dd;
+				
+				// set final point positions
+				dd = e.lineWidth/2;
+				// if drawing as lines, offset arrow tip by half the line width
+				if (e.arrowType == ArrowType.LINES) {
+					_p.x -= dd*dx;
+					_p.y -= dd*dy;
+					dd += e.lineWidth;
+				}
+				// offset the anchor point (the end point for the edge connector)
+				// so that edge doesn't "overshoot" the arrow head
+				dd = ah - dd;
+				x2 = _p.x - dd*dx;
+				y2 = _p.y - dd*dy;
+			}
+
+			// draw the edge
+			g.clear(); // clear it out
+			setLineStyle(e, g); // set the line style
+			if (e.shape == Shapes.BEZIER && ctrls != null && ctrls.length > 1) {
+				if (ctrls.length < 4)
+				{
+					g.moveTo(x1, y1);
+					g.curveTo(ctrls[0], ctrls[1], x2, y2);
+				}
+				else
+				{
+					Shapes.drawCubic(g, x1, y1, ctrls[0], ctrls[1],
+									 ctrls[2], ctrls[3], x2, y2);
+				}
+			}
+			else if (e.shape == Shapes.CARDINAL)
+			{
+				Shapes.consolidate(x1, y1, ctrls, x2, y2, _pts);
+				Shapes.drawCardinal(g, _pts, 2+ctrls.length/2);
+			}
+			else if (e.shape == Shapes.BSPLINE)
+			{
+				Shapes.consolidate(x1, y1, ctrls, x2, y2, _pts);
+				Shapes.drawBSpline(g, _pts, 2+ctrls.length/2);
+			}
+			else
+			{
+				g.moveTo(x1, y1);
+				if (ctrls != null) {
+					for (var i:uint=0; i<ctrls.length; i+=2)
+						g.lineTo(ctrls[i], ctrls[i+1]);
+				}
+				g.lineTo(x2, y2);
+			}
+			
+			// draw an arrow
+			if (e.arrowType != ArrowType.NONE) {
+				// get other arrow points
+				x1 = _p.x - ah*dx + aw*dy; y1 = _p.y - ah*dy - aw*dx;
+				x2 = _p.x - ah*dx - aw*dy; y2 = _p.y - ah*dy + aw*dx;
+								
+				if (e.arrowType == ArrowType.TRIANGLE) {
+					g.lineStyle();
+					g.moveTo(_p.x, _p.y);
+					g.beginFill(e.lineColor, e.lineAlpha);
+					g.lineTo(x1, y1);
+					g.lineTo(x2, y2);
+					g.endFill();
+				} else if (e.arrowType == ArrowType.LINES) {
+					g.moveTo(x1, y1);
+					g.lineTo(_p.x, _p.y);
+					g.lineTo(x2, y2);
+				}
+			}
+		}
+		
+		/**
+		 * Sets the line style for edge rendering.
+		 * @param e the EdgeSprite to render
+		 * @param g the Graphics context to draw with
+		 */
+		protected function setLineStyle(e:EdgeSprite, g:Graphics):void
+		{
+			var lineAlpha:Number = e.lineAlpha;
+			if (lineAlpha == 0) return;
+			
+			g.lineStyle(e.lineWidth, e.lineColor, lineAlpha, 
+				pixelHinting, scaleMode, caps, joints, miterLimit);
+		}
+
+	} // end of class EdgeRenderer
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/ArrowType.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/ArrowType.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/ArrowType.as	(revision 15)
@@ -0,0 +1,24 @@
+package gssim.gssimstudio.editor.flare.vis.data.render
+{	
+	/**
+	 * Utility class defining arrow types for directed edges.
+	 */
+	public class ArrowType
+	{
+		/** Indicates that no arrows should be drawn. */
+		public static const NONE:String = "none";
+		/** Indicates that a closed triangular arrow head should be drawn. */
+		public static const TRIANGLE:String = "triangle";
+		/** Indicates that two lines should be used to draw the arrow head. */
+		public static const LINES:String = "lines";
+		
+		/**
+		 * This constructor will throw an error, as this is an abstract class. 
+		 */
+		public function ArrowType()
+		{
+			throw new Error("This is an abstract class.");
+		}
+
+	} // end of class ArrowType
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/IRenderer.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/IRenderer.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/render/IRenderer.as	(revision 15)
@@ -0,0 +1,17 @@
+package gssim.gssimstudio.editor.flare.vis.data.render
+{
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	
+	/**
+	 * Interface for DataSprite rendering modules.
+	 */
+	public interface IRenderer
+	{
+		/**
+		 * Renders drawing content for the input DataSprite.
+		 * @param d the DataSprite to draw
+		 */
+		function render(d:DataSprite):void;
+		
+	} // end of interface IRenderer
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/Tree.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/Tree.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/Tree.as	(revision 15)
@@ -0,0 +1,248 @@
+package gssim.gssimstudio.editor.flare.vis.data
+{
+	import gssim.gssimstudio.editor.flare.vis.events.DataEvent;
+		
+	/**
+	 * Data structure for managing a collection of visual data objects in a
+	 * tree (hierarchy) structure. This class extends the functionality of
+	 * the Data class to model a hierarchy. The class can be used as an
+	 * alternative to the Data class when the data forms a strict tree, or to
+	 * model a spanning tree over a general graph.
+	 */
+	public class Tree extends Data
+	{	
+		/**
+		 * Sets the root node of this tree. This property can only be set
+		 * when the tree does not yet have a root node. */
+		public override function set root(n:NodeSprite):void {
+			if (_root == null) {
+				super.addNode(n); _root = n; _root.parentIndex = -1;
+				addDescendants(_root);
+			} else {
+				throw new ArgumentError("Can't set root unless the tree is empty." +
+				"If you want to set an entirely new root, call clear() first.");
+			}
+		}
+		
+		/** This property simply points back to this object. */
+		public override function get tree():Tree { return this; }
+		public override function set tree(t:Tree):void { /* do nothing */ }
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates and returns a new root NodeSprite for the tree. If the
+		 * tree already has a root, this method throws an error.
+		 * @return the newly added root
+		 */
+		public function addRoot():NodeSprite
+		{
+			if (_root != null) throw new Error(
+				"addRoot can only be called on an empty tree!");
+			return (_root = super.addNode());
+		}
+		
+		/**
+		 * Add a node to the tree. If the child node argument is null,
+		 * a new NodeSprite will be created. A new EdgeSprite connecting
+		 * the nodes will be created. Returns the new child node.
+		 * @param p the parent node
+		 * @param c the child node. If null, a new child node is created.
+		 * @return the new child node
+		 */
+		public function addChild(p:NodeSprite, c:NodeSprite=null):NodeSprite
+		{			
+			if (!_nodes.contains(p)) {
+				throw new ArgumentError("Parent node must be in the tree!");
+			}
+			c = super.addNode(c);
+			var e:EdgeSprite = newEdge(p, c, directedEdges, null);
+			c.parentIndex = p.addChildEdge(e);
+			c.parentEdge = e;
+			super.addEdge(e);
+			return c;
+		}
+		
+		/**
+		 * Adds the given edge as a child edge between a node already
+		 * in the tree and another node not yet in the tree.
+		 * @param e the edge to add to the tree
+		 * @return the newly added edge
+		 */
+		public function addChildEdge(e:EdgeSprite):EdgeSprite
+		{
+			var n1:NodeSprite = e.source, b1:Boolean = _nodes.contains(n1);
+			var n2:NodeSprite = e.target, b2:Boolean = _nodes.contains(n2);
+			
+			if (b1 && b2) {
+				throw new ArgumentError("One node must not be in the tree");
+			}
+			if (!(b1 || b2))
+				throw new ArgumentError("One node must already be in the tree");
+				
+			var p:NodeSprite = b1 ? n1 : n2;
+			var c:NodeSprite = b1 ? n2 : n1;
+			
+			c.parentEdge = e;
+			c.parentIndex = p.addChildEdge(e);
+			
+			super.addNode(c);
+			return super.addEdge(e);
+		}
+		
+		/**
+		 * Registers all tree descendants with this Tree instance. 
+		 * @param n a sub-tree root that has already been added to this Tree
+		 */
+		protected function addDescendants(n:NodeSprite):void
+		{
+			for (var i:int=0; i<n.childDegree; ++i) {
+				var e:EdgeSprite = n.getChildEdge(i);
+				var c:NodeSprite = e.other(n);
+				c.parentEdge = e;
+				c.parentIndex = i;
+				super.addNode(c);
+				super.addEdge(e);
+				addDescendants(c);
+			}
+		}
+		
+		/**
+		 * Clears the tree, removing all nodes and edges.
+		 */
+		public override function clear():void
+		{
+			super.clear(); _root = null;
+		}
+		
+		/**
+		 * Removes a node from the tree, removing the entire
+		 * subtree rooted at that node.
+		 * @param n the node to remove
+		 * @return true if the node was successfully removed, false otherwise
+		 */
+		public override function removeNode(n:NodeSprite):Boolean
+		{
+			if (n==_root) {
+				clear(); return true;
+			} else {
+				return removeEdge(n.parentEdge);
+			}
+		}
+		
+		/**
+		 * Removes an edge from tree tree, removing the entire
+		 * subtree rooted at the child node adjacent to the edge.
+		 * @param e the edge to remove from the tree
+		 * @return true if the edge was successfully removed, false otherwise
+		 */
+		public override function removeEdge(e:EdgeSprite):Boolean
+		{
+			if (e==null || !_edges.contains(e)) return false;
+			
+			// disconnect tree
+			var c:NodeSprite = (e.target.parentNode==e.source ? e.target : e.source);
+			var p:NodeSprite = c.parentNode;
+			var i:int = c.parentIndex;
+			p.removeChildEdge(e);
+			
+			// walk disconnected segment to fire updates
+			c.visitTreeDepthFirst(function(n:NodeSprite):void {
+				_edges.remove(n.parentEdge);
+				_nodes.remove(n);
+			});
+			_edges.remove(e);
+			
+			// update parent index values
+			for (; i<p.childDegree; ++i) {
+				p.getChildNode(i).parentIndex = i;
+			}
+			return true;	
+		}
+		
+		/** @private */
+		protected override function onRemoveNode(evt:DataEvent):void
+		{
+			fireEvent(evt);
+		}
+		
+		/** @private */
+		protected override function onRemoveEdge(evt:DataEvent):void
+		{
+			fireEvent(evt);
+		}
+
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Counts the number of leaf nodes in the tree.
+		 * @return the number of leaf nodes
+		 */
+		public function countLeaves():int
+		{
+			var leaves:int = 0;
+			for each (var ns:NodeSprite in _nodes.list) {
+				if (ns.childDegree == 0) ++leaves;
+			}
+			return leaves;
+		}
+
+		// --------------------------------------------------------------------
+
+		/**
+		 * Continuously swaps the given node with its parent node
+		 * until it is the root.
+		 * <p>
+		 * <strong>WARNING:</strong> this method causes connecting edges to be
+		 * reconfigured. If this tree is a spanning tree, this can cause havoc.
+		 * </p>
+		 * @param n the node to swap with its parent until it becomes the root
+		 */
+		public function swapToRoot(n:NodeSprite):void
+		{
+			while (n.parent != null) {
+				swapWithParent(n);
+			}
+		}
+
+		/**
+		 * Swaps the given node with its parent node.
+		 * <p>
+		 * <strong>WARNING:</strong> this method causes connecting edges to be
+		 * reconfigured. If this tree is a spanning tree, this can cause havoc.
+		 * </p>
+		 * @param n the node to swap with its parent
+		 */
+		public function swapWithParent(n:NodeSprite):void
+		{
+			var p:NodeSprite = n.parentNode, gp:NodeSprite;
+			var e:EdgeSprite, ge:EdgeSprite, idx:int;
+			if (p==null) return;
+			
+			gp = p.parentNode;
+			ge = p.parentEdge;
+			idx = p.parentIndex;
+			
+			// swap parent edge
+			e = n.parentEdge;
+			p.removeChild(n);
+			p.parentEdge = e;
+			p.parentIndex = n.addChildEdge(e);
+			
+			// connect to grandparents
+			if (gp==null) {
+				n.parentIndex = -1;
+				n.parentEdge = null;
+			} else {
+				if (ge.source == gp) {
+					ge.target = n;
+				} else {
+					ge.source = n;
+				}
+				n.parentIndex = idx;
+				n.parentEdge = ge;
+			}
+		}
+
+	} // end of class Tree
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/DataSprite.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/DataSprite.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/DataSprite.as	(revision 15)
@@ -0,0 +1,230 @@
+package gssim.gssimstudio.editor.flare.vis.data
+{
+	import gssim.gssimstudio.editor.flare.display.DirtySprite;
+	import gssim.gssimstudio.editor.flare.util.Colors;
+	import gssim.gssimstudio.editor.flare.vis.data.render.IRenderer;
+	import gssim.gssimstudio.editor.flare.vis.data.render.ShapeRenderer;
+
+	/**
+	 * Base class for display objects that represent visualized data.
+	 * DataSprites support a number of visual properties beyond those provided
+	 * by normal sprites. These include properties for colors, shape, size,
+	 * setting the position in polar coordinates (<code>angle</code> and
+	 * <code>radius</code>), and others.
+	 * 
+	 * <p>The actual appearance of DataSprite instances are determined using
+	 * pluggable renderers that draw graphical content for the sprite. These
+	 * renderers can be changed at runtime to dynamically control appearances.
+	 * Furthermore, since these are sprites, they can contain arbitrary display
+	 * objects as children on the display list, including entire nested
+	 * visualizations.</p>
+	 * 
+	 * <p>DataSprites provides two additional properties worth noting. First,
+	 * the <code>data</code> property references an object containing backing
+	 * data to be visualized. This data object is typically the data record
+	 * (or tuple) this DataSprite visually represents, and its values are often
+	 * used to determined visual encodings. Second, the <code>props</code>
+	 * objects is a dynamic object provided for attaching arbitrary properties
+	 * to a DataSprite instance. For example, some layout algorithms require
+	 * additional parameters on a per-item basis and store these values in the
+	 * <code>props</code> property.</p>
+	 */
+	public class DataSprite extends DirtySprite
+	{
+		// -- Properties ------------------------------------------------------
+		
+		/** The renderer for drawing this DataSprite. */
+		protected var _renderer:IRenderer = ShapeRenderer.instance;
+		/** Object storing backing data values. */
+		protected var _data:Object = {};
+		/** Object for attaching additional properties to this sprite. */
+		protected var _prop:Object = {};
+		
+		/** Fixed flag to prevent this sprite from being re-positioned. */
+		protected var _fixed:int = 0;
+		/** The fill color for this data sprite. This value is specified as an
+		 *  unsigned integer representing an ARGB color. Notice that this
+		 *  includes the alpha channel in the color value. */
+		protected var _fillColor:uint = 0xffcccccc;
+		/** The line color for this data sprite. This value is specified as an
+		 *  unsigned integer representing an ARGB color. Notice that this
+		 *  includes the alpha channel in the color value. */
+		protected var _lineColor:uint = 0xff000000;
+		/** The line width for this data sprite. */
+		protected var _lineWidth:Number = 0;
+
+		/** Optional array of x,y values for specifying arbitrary shapes. */
+		protected var _points:Array;
+		/** Code indicating the shape value of this data sprite. */
+		protected var _shape:String = "circle";
+		/** The size value of this data sprite (1 by default). */
+		protected var _size:Number = 1;
+		
+		/** Auxiliary property often used as a width parameter. */
+		protected var _w:Number = 0;
+		/** Auxiliary property often used as a height parameter. */
+		protected var _h:Number = 0;
+		/** Auxiliary property often used as a shape parameter. */
+		protected var _u:Number = 0;
+		/** Auxiliary property often used as a shape parameter. */
+		protected var _v:Number = 0;
+		
+		// -- General Properties -------------------------------
+		
+		/** The renderer for drawing this DataSprite. */
+		public function get renderer():IRenderer { return _renderer; }
+		public function set renderer(r:IRenderer):void { _renderer = r; dirty(); }
+		
+		/** Object storing backing data values. */
+		public function get data():Object { return _data; }
+		public function set data(d:Object):void { _data = d; }
+		
+		/** Object for attaching additional properties to this sprite. */
+		public function get props():Object { return _prop; }
+		public function set props(p:Object):void { _prop = p; _prop.self = this; }
+		
+		// -- Interaction Properties ---------------------------
+		
+		/** Fixed flag to prevent this sprite from being re-positioned. */
+		public function get fixed():Boolean { return _fixed > 0; }
+		/**
+		 * Increments the fixed counter. If the fixed counter is greater than
+		 * zero, the data sprite should be fixed. A counter is used so that if
+		 * different components both adjust the fixed settings, they won't
+		 * overwrite each other.
+		 * @param num the amount to increment the counter by (default 1)
+		 */
+		public function fix(num:uint=1):void { _fixed += num; }
+		/**
+		 * Decrements the fixed counter. If the fixed counter is greater than
+		 * zero, the data sprite should be fixed. A counter is used so that if
+		 * different components both adjust the fixed settings, they won't
+		 * overwrite each other. This method does not allow the fixed counter
+		 * to go below zero.
+		 * @param num the amount to decrement the counter by (default 1)
+		 */
+		public function unfix(num:uint=1):void { _fixed = Math.max(0, _fixed-num); }
+		 
+		// -- Visual Properties --------------------------------
+
+		/** Auxiliary property often used as a shape parameter. */
+		public function get u():Number { return _u; }
+		public function set u(u:Number):void { _u = u; dirty(); }
+		
+		/** Auxiliary property often used as a shape parameter. */
+		public function get v():Number { return _v; }
+		public function set v(v:Number):void { _v = v; dirty(); }
+		
+		/** Auxiliary property often used as a width parameter. */
+		public function get w():Number { return _w; }
+		public function set w(v:Number):void { _w = v; dirty(); }
+		
+		/** Auxiliary property often used as a height parameter. */
+		public function get h():Number { return _h; }
+		public function set h(v:Number):void { _h = v; dirty(); }
+		
+		/** The fill color for this data sprite. This value is specified as an
+		 *  unsigned integer representing an ARGB color. Notice that this
+		 *  includes the alpha channel in the color value. */
+		public function get fillColor():uint { return _fillColor; }
+		public function set fillColor(c:uint):void { _fillColor = c; dirty();	}
+		/** The alpha channel (a value between 0 and 1) for the fill color. */
+		public function get fillAlpha():Number { return Colors.a(_fillColor) / 255; }
+		public function set fillAlpha(a:Number):void {
+			_fillColor = Colors.setAlpha(_fillColor, uint(255*a)%256);
+			dirty();
+		}
+		/** The hue component of the fill color in HSV color space. */
+		public function get fillHue():Number { return Colors.hue(_fillColor); }
+		public function set fillHue(h:Number):void {
+			_fillColor = Colors.hsv(h, Colors.saturation(_fillColor),
+				Colors.value(_fillColor), Colors.a(_fillColor));
+			dirty();
+		}
+		/** The saturation component of the fill color in HSV color space. */
+		public function get fillSaturation():Number { return Colors.saturation(_fillColor); }
+		public function set fillSaturation(s:Number):void {
+			_fillColor = Colors.hsv(Colors.hue(_fillColor), s,
+				Colors.value(_fillColor), Colors.a(_fillColor));
+			dirty();
+		}
+		/** The value (brightness) component of the fill color in HSV color space. */
+		public function get fillValue():Number { return Colors.value(_fillColor); }
+		public function set fillValue(v:Number):void {
+			_fillColor = Colors.hsv(Colors.hue(_fillColor),
+				Colors.saturation(_fillColor), v, Colors.a(_fillColor));
+			dirty();
+		}
+				
+		/** The line color for this data sprite. This value is specified as an
+		 *  unsigned integer representing an ARGB color. Notice that this
+		 *  includes the alpha channel in the color value. */
+		public function get lineColor():uint { return _lineColor; }
+		public function set lineColor(c:uint):void { _lineColor = c; dirty(); }
+		/** The alpha channel (a value between 0 and 1) for the line color. */
+		public function get lineAlpha():Number { return Colors.a(_lineColor) / 255; }
+		public function set lineAlpha(a:Number):void {
+			_lineColor = Colors.setAlpha(_lineColor, uint(255*a)%256);
+			dirty();
+		}
+		/** The hue component of the line color in HSV color space. */
+		public function get lineHue():Number { return Colors.hue(_lineColor); }
+		public function set lineHue(h:Number):void {
+			_lineColor = Colors.hsv(h, Colors.saturation(_lineColor),
+				Colors.value(_lineColor), Colors.a(_lineColor));
+			dirty();
+		}
+		/** The saturation component of the line color in HSV color space. */
+		public function get lineSaturation():Number { return Colors.saturation(_lineColor); }
+		public function set lineSaturation(s:Number):void {
+			_lineColor = Colors.hsv(Colors.hue(_lineColor), s,
+				Colors.value(_lineColor), Colors.a(_lineColor));
+			dirty();
+		}
+		/** The value (brightness) component of the line color in HSV color space. */
+		public function get lineValue():Number { return Colors.value(_lineColor); }
+		public function set lineValue(v:Number):void {
+			_lineColor = Colors.hsv(Colors.hue(_lineColor),
+				Colors.saturation(_lineColor), v, Colors.a(_lineColor));
+			dirty();
+		}
+		
+		/** The line width for this data sprite. */
+		public function get lineWidth():Number { return _lineWidth; }
+		public function set lineWidth(w:Number):void { _lineWidth = w; dirty(); }
+
+		/** The size value of this data sprite (1 by default). */
+		public function get size():Number { return _size; }
+		public function set size(s:Number):void { _size = s; dirty(); }
+
+		/** Name of the shape value of this data sprite. 
+		 *  @see flare.vis.util.Shapes */
+		public function get shape():String { return _shape; }
+		public function set shape(s:String):void { _shape = s; dirty(); }
+		
+		/** Optional array of x,y values for specifying arbitrary shapes. */
+		public function get points():Array { return _points; }
+		public function set points(p:Array):void { _points = p; dirty(); }
+		
+		// -- Methods ---------------------------------------------------------
+
+		/**
+		 * Creates a new DataSprite.
+		 */		
+		public function DataSprite() {
+			super();
+			_prop.self = this;
+		}
+		
+		/** @inheritDoc */
+		public override function render() : void
+		{
+			if (_renderer != null) {
+				_renderer.render(this);
+			} else {
+				this.graphics.clear();
+			}
+		}
+
+	} // end of class DataSprite
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/ScaleBinding.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/ScaleBinding.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/ScaleBinding.as	(revision 15)
@@ -0,0 +1,370 @@
+package gssim.gssimstudio.editor.flare.vis.data
+{
+	import gssim.gssimstudio.editor.flare.scale.LinearScale;
+	import gssim.gssimstudio.editor.flare.scale.LogScale;
+	import gssim.gssimstudio.editor.flare.scale.OrdinalScale;
+	import gssim.gssimstudio.editor.flare.scale.QuantileScale;
+	import gssim.gssimstudio.editor.flare.scale.QuantitativeScale;
+	import gssim.gssimstudio.editor.flare.scale.RootScale;
+	import gssim.gssimstudio.editor.flare.scale.Scale;
+	import gssim.gssimstudio.editor.flare.scale.ScaleType;
+	import gssim.gssimstudio.editor.flare.scale.TimeScale;
+	import gssim.gssimstudio.editor.flare.util.Stats;
+	import gssim.gssimstudio.editor.flare.vis.events.DataEvent;
+	
+	/**
+	 * Utility class that binds a data property to a descriptive scale.
+	 * A ScaleBinding provides a layer of indirection between a data field and
+	 * a data scale describing that field. The created scale can be used for
+	 * layout and encoding of data values. When scale parameters such as the
+	 * scale type or value range are updated, an underlying scale instance will
+	 * be updated accordingly or a new instance will be created as needed.
+	 */
+	public class ScaleBinding extends Scale
+	{
+		/** @private */
+		protected var _scale:Scale = null;
+		/** @private */
+		protected var _scaleType:String = null;
+		/** @private */
+		protected var _pmin:Object = null;
+		/** @private */
+		protected var _pmax:Object = null;
+		/** @private */
+		protected var _base:Number = 10;
+		/** @private */
+		protected var _bins:int = 5;
+		/** @private */
+		protected var _power:Number = NaN;
+		/** @private */
+		protected var _zeroBased:Boolean = false;
+		/** @private */
+		protected var _ordinals:Array = null;
+		
+		/** @private */
+		protected var _property:String;
+		/** @private */
+		protected var _group:String;
+		/** @private */
+		protected var _data:Data;
+		/** @private */
+		protected var _stats:Stats;
+		
+		/** If true, updates to the underlying data will be ignored, as will
+		 *  any calls to <code>updateBinding</code>. Set this flag if you want
+		 *  to prevent the scale values from changing automatically. */
+		public var ignoreUpdates:Boolean = false;
+		
+		/** The type of scale to create. */
+		public override function get scaleType():String {
+			return _scaleType ? _scaleType : scale.scaleType;
+		}
+		public function set scaleType(type:String):void {
+			_scaleType = type;
+			_scale = null;
+		}
+		
+		/** The preferred minimum data value for the scale. If null, the scale
+		 *  minimum will be determined from the data directly. */
+		public function get preferredMin():Object { return _pmin; }
+		public function set preferredMin(val:Object):void {
+			_pmin = val;
+			if (_scale && _pmin) {
+				_scale.min = _pmin;
+				if (_zeroBased) zeroAlignScale(_scale);
+			}
+		}
+		
+		/** The preferred maximum data value for the scale. If null, the scale
+		 *  maximum will be determined from the data directly. */
+		public function get preferredMax():Object { return _pmax; }
+		public function set preferredMax(val:Object):void {
+			_pmax = val;
+			if (_scale && _pmax) {
+				_scale.max = _pmax;
+				if (_zeroBased) zeroAlignScale(_scale);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function get max():Object { return scale.max; }
+		public override function set max(v:Object):void { scale.max = v; }
+		
+		/** @inheritDoc */
+		public override function get min():Object { return scale.min; }
+		public override function set min(v:Object):void { scale.min = v; }
+		
+		/** The number base to use for a quantitative scale (10 by default). */
+		public function get base():Number { return _base; }
+		public function set base(val:Number):void {
+			_base = val;
+			if (_scale is QuantitativeScale) {
+				QuantitativeScale(_scale).base = _base;
+			}
+		}
+		
+		/** A free parameter that indicates the exponent for a RootScale. */
+		public function get power():Number { return _power; }
+		public function set power(val:Number):void {
+			_power = val;
+			if (_scale is RootScale) {
+				RootScale(_scale).power = _power;
+			}
+		}
+		
+		/** The number of bins for quantile scales. */
+		public function get bins():int { return _bins; }
+		public function set bins(count:int):void {
+			_bins = count;
+			if (_scale is QuantileScale) {
+				_scale = null;
+			}
+		}
+		
+		/** Flag indicating if the scale bounds should be flush with the data.
+		 *  @see flare.scale.Scale#flush */
+		public override function get flush():Boolean { return _flush; }
+		public override function set flush(val:Boolean):void {
+			_flush = val;
+			if (_scale) _scale.flush = _flush;
+		}
+		
+		/** Formatting pattern for formatting labels for scale values.
+		 *  @see flare.vis.scale.Scale#labelFormat. */
+		public override function get labelFormat():String { return _format; }
+		public override function set labelFormat(fmt:String):void {
+			_format = fmt;
+			if (_scale) _scale.labelFormat = fmt;
+		}
+		
+		/** Flag indicating if a zero-based scale should be used. If set to
+		 *  true, and the scale type is numerical, the minimum or maximum
+		 *  scale value will automatically be adjusted to include the zero
+		 *  point as necessary. */
+		public function get zeroBased():Boolean { return _zeroBased; }
+		public function set zeroBased(val:Boolean):void {
+			_zeroBased = val;
+			if (_scale) zeroAlignScale(_scale);
+		}
+		
+		/** An ordered array of values for defining an ordinal scale. */
+		public function get ordinals():Array { return _ordinals; }
+		public function set ordinals(ord:Array):void {
+			_ordinals = ord;
+			if (ScaleType.isOrdinal(_scaleType)) {
+				_stats = null;
+				_scale = null;
+			}
+		}
+		
+		// -----------------------------------------------------
+		
+		/** The data instance to bind to. */
+		public function get data():Data { return _data; }
+		public function set data(data:Data):void {
+			if (_data != null) { // remove existing listeners
+				_data.removeEventListener(DataEvent.ADD,   onDataEvent);
+				_data.removeEventListener(DataEvent.REMOVE, onDataEvent);
+				_data.removeEventListener(DataEvent.UPDATE, onDataEvent);
+			}
+			_data = data;
+			if (_data != null) { // add new listeners
+				_data.addEventListener(DataEvent.ADD,
+					onDataEvent, false, 0, true);
+				_data.addEventListener(DataEvent.REMOVE,
+					onDataEvent, false, 0, true);
+				_data.addEventListener(DataEvent.UPDATE,
+					onDataEvent, false, 0, true);
+			}
+		}
+		
+		/** The data group to bind to. */
+		public function get group():String { return _group; }
+		public function set group(name:String):void {
+			if (name != _group) {
+				_group = name;
+				_stats = null;
+				_scale = null;
+			}
+		}
+		
+		/** The data property to bind to. */
+		public function get property():String { return _property; }
+		public function set property(name:String):void {
+			if (name != _property) {
+				_property = name;
+				_stats = null;
+				_scale = null;
+			}
+		}
+		
+		/** The underlying scale created by this binding. */
+		protected function get scale():Scale {
+			if (!_data || !_group || !_property) {
+				throw new Error("Can't create scale with data to bind to.");
+			}
+			if (!_scale) {
+				_stats = _data.group(_group).stats(_property);
+				_scale = buildScale(_stats);
+			}
+			return _scale;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new ScaleBinding.
+		 */
+		public function ScaleBinding()
+		{
+		}
+		
+		/**
+		 * Checks to see if the binding is current. If not, the internal stats
+		 * and scale for this binding will be cleared and lazily recomputed.
+		 * @return true if the binding was updated, false otherwise
+		 */
+		public function updateBinding():Boolean
+		{
+			if (ignoreUpdates) return false;
+			var stats:Stats = _data.group(_group).stats(_property);
+			if (stats !== _stats) { // object identity test
+				_stats = null;
+				_scale = null;
+				return true;
+			}
+			return false;
+		}
+		
+		/**
+		 * Internal listener for data events that clears the current scale
+		 * instance as needed.
+		 * @param evt a DataEvent
+		 */
+		private function onDataEvent(evt:DataEvent):void
+		{
+			if (ignoreUpdates) return;
+			if (evt.list.name == _group) {
+				if (evt.type == DataEvent.UPDATE) {
+					updateBinding();
+				} else {
+					_stats = null;
+					_scale = null;
+				}
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function clone() : Scale
+		{
+			return scale.clone();
+		}
+		
+		/**
+		 * Returns the index of the input value in the ordinal array if the
+		 * scale is ordinal or categorical, otherwise returns -1.
+		 * @param value the value to lookup
+		 * @return the index of the input value. If the value is not contained
+		 *  in the ordinal array, this method returns -1.
+		 */
+		public function index(value:Object):int
+		{
+			var s:OrdinalScale = scale as OrdinalScale;
+			return (s ? s.index(value) : -1);
+		}
+		
+		/** The number of distinct values in this scale, if ordinal. */
+		public function get length():int
+		{
+			var s:OrdinalScale = scale as OrdinalScale;
+			return (s ? s.length : -1);
+		}
+		
+		/** @inheritDoc */
+		public override function interpolate(value:Object) : Number
+		{
+			return scale.interpolate(value);
+		}
+
+		/** @inheritDoc */
+		public override function lookup(f:Number) : Object
+		{
+			return scale.lookup(f);
+		}
+
+		/** @inheritDoc */
+		public override function values(num:int=-1) : Array
+		{
+			return scale.values(num);
+		}
+		
+		/** @inheritDoc */
+		public override function label(value:Object) : String
+		{
+			return scale.label(value);
+		}
+		
+		/** @private */
+		protected function buildScale(stats:Stats):Scale
+		{
+			var type:String = _scaleType ? _scaleType : ScaleType.UNKNOWN;
+			var vals:Array = _ordinals ? _ordinals : stats.distinctValues;
+			var scale:Scale;
+			
+			switch (stats.dataType) {
+				case Stats.NUMBER:
+					switch (type) {
+						case ScaleType.LINEAR:
+						case ScaleType.UNKNOWN:
+							scale = new LinearScale(stats.minimum, stats.maximum, _base, _flush, _format);
+							break;
+						case ScaleType.ROOT:
+							var pow:Number = isNaN(_power) ? 2 : _power;
+							scale = new RootScale(stats.minimum, stats.maximum, _base, _flush, pow, _format);
+							break;
+						case ScaleType.LOG:
+							scale = new LogScale(stats.minimum, stats.maximum, _base, _flush, _format);
+							break;
+						case ScaleType.QUANTILE:
+							scale = new QuantileScale(_bins, stats.values, true, _format);
+							break;
+						default:
+							scale = new OrdinalScale(vals, _flush, false, _format);
+							break;
+					}
+					break;
+				case Stats.DATE:
+					switch (type) {
+						case ScaleType.UNKNOWN:
+						case ScaleType.LINEAR:
+						case ScaleType.TIME:
+							scale = new TimeScale(stats.minDate, stats.maxDate, _flush, _format);
+							break;
+						default:
+							scale = new OrdinalScale(vals, _flush, false, _format);
+							break;
+					}
+					break;
+				default:
+					scale = new OrdinalScale(vals, _flush, false, _format);
+					break;
+			}
+			
+			if (_pmin) scale.min = _pmin;
+			if (_pmax) scale.max = _pmax;
+			if (_zeroBased) zeroAlignScale(scale);
+			
+			return scale;
+		}
+		
+		private static function zeroAlignScale(scale:Scale):void
+		{
+			if (scale is QuantitativeScale) {
+				var qs:QuantitativeScale = QuantitativeScale(scale);
+				if (qs.scaleMin > 0) qs.dataMin = 0;
+				if (qs.scaleMax < 0) qs.dataMax = 0;
+			}
+		}
+
+	} // end of class ScaleBinding
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/DataList.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/DataList.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/DataList.as	(revision 15)
@@ -0,0 +1,606 @@
+package gssim.gssimstudio.editor.flare.vis.data
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Filter;
+	import gssim.gssimstudio.editor.flare.util.IEvaluable;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.Sort;
+	import gssim.gssimstudio.editor.flare.util.Stats;
+	import gssim.gssimstudio.editor.flare.util.math.DenseMatrix;
+	import gssim.gssimstudio.editor.flare.util.math.IMatrix;
+	import gssim.gssimstudio.editor.flare.vis.events.DataEvent;
+	
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	import flash.events.IEventDispatcher;
+	import flash.utils.Dictionary;
+	import flash.utils.Proxy;
+	import flash.utils.flash_proxy;
+
+	[Event(name="add",    type="flare.vis.events.DataEvent")]
+	[Event(name="remove", type="flare.vis.events.DataEvent")]
+
+	/**
+	 * Data structure for a collection of <code>DataSprite</code> instances.
+	 * Items contained in this list can be accessed using array notation
+	 * (<code>[]</code>), iterated over using the <code>for each</code>
+	 * construct, or can be processed by passing a visitor function to the
+	 * <code>visit</code> method.
+	 * 
+	 * <p>Data lists provide methods for sorting elements both in a one-time
+	 * and persistent fashion, for setting the properties of contained
+	 * items in a batch-processing style (see the <code>setProperty</code>
+	 * and <code>setProperties</code> methods), and for computing and
+	 * caching summary statistics of data variables (see the
+	 * <code>stats</code> method.</p>
+	 * 
+	 * <p>Data lists also support listeners for add and remove events. These
+	 * events are fired <em>before</em> the add or remove is executed. These
+	 * data events can be canceled by calling <code>preventDefault()</code>
+	 * on the <code>DataEvent</code> object, thereby preventing the add or
+	 * remove from being performed. Using this mechanism, clients can add
+	 * custom constraints on the contents of a data list by adding new
+	 * listeners that monitor add and remove events and cancel them when
+	 * desired.</p>
+	 */
+	public class DataList extends Proxy implements IEventDispatcher
+	{
+		private var _dispatch:EventDispatcher = new EventDispatcher();
+		
+		/** Hashed set of items in the data list. */
+		private var _map:Dictionary = new Dictionary();
+		/** Array of items in the data set. */
+		private var _list:Array = [];
+		/** Default property values to be applied to new items. */
+		private var _defs:Object = null;
+		/** Cache of Stats objects for item properties. */
+		private var _stats:Object = {};
+		/** The underlying array storing the list. */
+		internal function get list():Array { return _list; }
+		
+		/** The name of this data list. */
+		public function get name():String { return _name; }
+		private var _name:String;
+		
+		/** Internal count of visitors traversing the current list. */
+		private var _visiting:int = 0;
+		private var _sort:Sort;
+		
+		/** The number of items contained in this list. */
+		public function get length():int { return _list.length; }
+		
+		/** A standing sort criteria for items in the list. */
+		public function get sort():Sort { return _sort; }
+		public function set sort(s:*):void {
+			_sort = s==null ? s : (s is Sort ? Sort(s) : new Sort(s));
+			if (_sort != null) _sort.sort(_list);
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new DataList instance. 
+		 * @param editable indicates if this list should be publicly editable.
+		 */
+		public function DataList(name:String) {
+			_name = name;
+		}
+		
+		// -- Basic Operations: Contains, Add, Remove, Clear ------------------
+		
+		/**
+		 * Indicates if the given object is contained in this list.
+		 * @param d the object to check for containment
+		 * @return true if the list contains the object, false otherwise.
+		 */
+		public function contains(d:DataSprite):Boolean
+		{
+			return (_map[d] != undefined);
+		}
+		
+		/**
+		 * Add a DataSprite to the list.
+		 * @param d the DataSprite to add
+		 * @return the added DataSprite, or null if the add failed
+		 */
+		public function add(d:DataSprite):DataSprite
+		{
+			if (!fireEvent(DataEvent.ADD, d))
+				return null;
+			
+			_map[d] = _list.length;
+			_stats = {};
+			if (_sort != null) {
+				var idx:int = Arrays.binarySearch(_list, d, null,
+				                                  _sort.comparator);
+				_list.splice(-(idx+1), 0, d);
+			} else {
+				_list.push(d);
+			}
+			return d;
+		}
+		
+		/**
+		 * Remove a data sprite from the list.
+		 * @param ds the DataSprite to remove
+		 * @return true if the object was found and removed, false otherwise
+		 */
+		public function remove(d:DataSprite):Boolean
+		{
+			if (_map[d] == undefined) return false;
+			if (!fireEvent(DataEvent.REMOVE, d))
+				return false;
+			if (_visiting > 0) {
+				// if called from a visitor, use a copy-on-write strategy
+				_list = Arrays.copy(_list);
+				_visiting = 0; // reset the visitor count
+			}
+			Arrays.remove(_list, d);
+			delete _map[d];
+			_stats = {};	
+			return true;
+		}
+		
+		/**
+		 * Remove a DataSprite from the list.
+		 * @param idx the index of the DataSprite to remove
+		 * @return the removed DataSprite
+		 */
+		public function removeAt(idx:int):DataSprite
+		{
+			var d:DataSprite = _list[idx];
+			if (d == null || !fireEvent(DataEvent.REMOVE, d))
+				return null;
+			
+			Arrays.removeAt(_list, idx);
+			if (d != null) {
+				delete _map[d];
+				_stats = {};
+			}
+			return d;
+		}
+		
+		/**
+		 * Remove all DataSprites from this list.
+		 */
+		public function clear():Boolean
+		{
+			if (_list.length == 0) return true;
+			if (!fireEvent(DataEvent.REMOVE, _list))
+				return false;
+			_map = new Dictionary();
+			_list = [];
+			_stats = {};
+			return true;
+		}
+		
+		// -- Data Representations --------------------------------------------
+		
+		/**
+		 * Returns an array of data objects for each item in this data list.
+		 * Data objects are retrieved from the "data" property for each item.
+		 * @return an array of data objects for items in this data list
+		 */
+		public function toDataArray():Array
+		{
+			var a:Array = new Array(_list.length);
+			for (var i:int=0; i<a.length; ++i) {
+				a[i] = _list[i].data;
+			}
+			return a;
+		}
+		
+		/**
+		 * Creates a new adjacency matrix representing the connections between
+		 * items in this DataList. This method should only be applied when the
+		 * items contained in this list are <code>NodeSprite</code> instances.
+		 * The method takes an optional function to compute edge weights.
+		 * @param w the edge weight function. This function should take an
+		 *  <code>EdgeSprite</code> as input and return a <code>Number</code>.
+		 * @param mat a matrix instance in which to store the adjacency matrix
+		 *  values. If this value is null, a new <code>DenseMatrix</code> will
+		 *  be constructed.
+		 * @return the adjacency matrix
+		 */
+		public function adjacencyMatrix(w:Function=null,
+			mat:IMatrix=null):IMatrix
+		{
+			var N:int = length, k:int = 0;
+			
+			// build dictionary of nodes
+			var idx:Dictionary = new Dictionary();
+			for (k=0; k<N; ++k) {
+				if (!(_list[k] is NodeSprite))
+					throw new Error("Only NodeSprites can be used to " + 
+							"create an adjacency matrix.");
+				idx[_list[k]] = k;
+			}
+			
+			// initialize matrix
+			if (mat) {
+				mat.init(N, N)
+			} else {
+				mat = new DenseMatrix(N, N);
+			}
+			
+			// build adjacency matrix
+			for each (var n:NodeSprite in _list) {
+				var i:int = idx[n];
+				n.visitEdges(function(e:EdgeSprite):void {
+					if (idx[e.target] == undefined) return;
+					var j:int = idx[e.target];
+					var v:Number = w==null ? 1 : w(e);
+					mat.set(i,j,v); mat.set(j,i,v);
+				}, NodeSprite.OUT_LINKS);
+			}
+			return mat;
+		}
+		
+		/**
+		 * Creates a new distance matrix based on a distance function.
+		 * @param d the distance function. This should take two
+		 *  <code>DataSprite</code> instances and return a <code>Number</code>
+		 * @param mat a matrix instance in which to store the adjacency matrix
+		 *  values. If this value is null, a new <code>DenseMatrix</code> will
+		 *  be constructed.
+		 * @return the distance matrix
+		 */
+		public function distanceMatrix(d:Function, mat:IMatrix=null):IMatrix
+		{
+			var N:int = length, i:uint, j:uint;
+			
+			if (mat) {
+				mat.init(N, N);
+			} else {
+				mat = new DenseMatrix(N, N);
+			}
+			for (i=0; i<N; ++i) {
+				for (j=i+1; j<N; ++j) {
+					var v:Number = d(_list[i], _list[j]);
+					mat.set(i,j,v); mat.set(j,i,v);
+				}
+			}
+			return mat;
+		}
+		
+
+		// -- Sort ------------------------------------------------------------
+		
+		/**
+		 * Sort DataSprites according to their properties. This method performs
+		 * a one-time sorting. To establish a consistent sort order robust over
+		 * the addition of new items, use the <code>sort</code> property.
+		 * @param args the sort arguments.
+		 * 	If a String is provided, the data will be sorted in ascending order
+		 *   according to the data field named by the string.
+		 *  If an Array is provided, the data will be sorted according to the
+		 *   fields in the array. In addition, field names can optionally
+		 *   be followed by a boolean value. If true, the data is sorted in
+		 *   ascending order (the default). If false, the data is sorted in
+		 *   descending order.
+		 */
+		public function sortBy(...args):void
+		{
+			if (args.length == 0) return;
+			if (args[0] is Array) args = args[0];
+			
+			var f:Function = Sort.$(args);
+			_list.sort(f);
+		}
+
+		// -- Visitation ------------------------------------------------------
+		
+		/**
+		 * Iterates over the contents of the list, invoking a visitor function
+		 * on each element of the list. If the visitor function returns a
+		 * Boolean true value, the iteration will stop with an early exit.
+		 * @param visitor the visitor function to be invoked on each item
+		 * @param filter an optional boolean-valued function indicating which
+		 *  items should be visited
+		 * @param reverse optional flag indicating if the list should be
+		 *  visited in reverse order
+		 * @return true if the visitation was interrupted with an early exit
+		 */		
+		public function visit(visitor:Function, filter:*=null,
+			reverse:Boolean=false):Boolean
+		{
+			_visiting++; // mark a visit in process
+			var a:Array = _list; // use our own reference to the list
+			var i:uint, n:uint=a.length, b:Boolean = false;
+			var f:Function = Filter.$(filter);
+			
+			if (reverse && f==null) {
+				for (i=n; --i>=0;)
+					if (visitor(a[i]) as Boolean) {
+						b = true; break;
+					}
+			}
+			else if (reverse) {
+				for (i=n; --i>=0;)
+					if (f(a[i]) && (visitor(a[i]) as Boolean)) {
+						b = true; break;
+					}
+			}
+			else if (f==null) {
+				for (i=0; i<n; ++i)
+					if (visitor(a[i]) as Boolean) {
+						b = true; break;
+					}
+			}
+			else {
+				for (i=0; i<n; ++i)
+					if (f(a[i]) && (visitor(a[i]) as Boolean)) {
+						b = true; break;
+					}
+			}
+			_visiting = Math.max(0, --_visiting); // unmark a visit in process
+			return b;
+		}
+		
+		// -- Default Values --------------------------------------------------
+		
+		/**
+		 * Sets a default property value for newly created items.
+		 * @param name the name of the property
+		 * @param value the value of the property
+		 */
+		public function setDefault(name:String, value:*):void
+		{
+			if (_defs == null) _defs = {};
+			_defs[name] = value;
+		}
+		
+		/**
+		 * Removes a default value for newly created items.
+		 * @param name the name of the property
+		 */
+		public function removeDefault(name:String):void
+		{
+			if (_defs != null) delete _defs[name];
+		}
+		
+		/**
+		 * Sets default values for newly created items.
+		 * @param values the default properties to set
+		 */
+		public function setDefaults(values:Object):void
+		{
+			if (_defs == null) _defs = {};
+			for (var name:String in values)
+				_defs[name] = values[name];
+		}
+		
+		/**
+		 * Clears all default value settings for this list.
+		 */
+		public function clearDefaults():void
+		{
+			_defs = null;
+		}
+		
+		/**
+		 * Applies the default values to an object.
+		 * @param o the object on which to set the default values
+		 * @param vals the set of default property values
+		 */
+		public function applyDefaults(o:Object):void
+		{
+			if (_defs == null) return;
+			
+			for (var name:String in _defs) {
+				var value:* = _defs[name];
+				if (value is IEvaluable) {
+					value = IEvaluable(value).eval(o);
+				} else if (value is Function) {
+					value = (value as Function)(o);
+				}
+				Property.$(name).setValue(o, value);
+			}
+		}
+		
+		// -- Set Values ------------------------------------------------------
+		
+		/**
+		 * Sets a property value on all items in the list. The value can take
+		 *  a number of forms:
+		 * <ul>
+		 *  <li>If the value is a <code>Function</code>, it will be evaluated
+		 *      for each element and the result will be used as the property
+		 *      value for that element.</li>
+		 *  <li>If the value is an <code>IEvaluable</code> instance, such as
+		 *      <code>flare.util.Property</code> or
+		 *      <code>flare.query.Expression</code>, it will be evaluated for
+		 *      each element and the result will be used as the property value
+		 *      for that element.</li>
+		 *  <li>In all other cases, the property value will be treated as a
+		 *      literal and assigned for all elements.</li>
+		 * </ul>
+		 * @param name the name of the property
+		 * @param value the value of the property
+		 * @param t a transitioner or time span for updating object values. If
+		 *  the input is a transitioner, it will be used to store the updated
+		 *  values. If the input is a number, a new Transitioner with duration
+		 *  set to the input value will be used. The input is null by default,
+		 *  in which case object values are updated immediately.
+		 * @param filter an optional Boolean-valued filter function for
+		 * 	limiting which items are visited
+		 * @return the transitioner used to update the values
+		 */
+		public function setProperty(name:String, value:*, t:*=null,
+			filter:*=null):Transitioner
+		{
+			var trans:Transitioner = Transitioner.instance(t);
+			var f:Function = Filter.$(filter);
+			Arrays.setProperty(_list, name, value, f, trans);
+			return trans;
+		}
+		
+		/**
+		 * Sets property values on all sprites in a given group. The values
+		 * within the <code>vals</code> argument can take a number of forms:
+		 * <ul>
+		 *  <li>If a value is a <code>Function</code>, it will be evaluated
+		 *      for each element and the result will be used as the property
+		 *      value for that element.</li>
+		 *  <li>If a value is an <code>IEvaluable</code> instance, such as
+		 *      <code>flare.util.Property</code> or
+		 *      <code>flare.query.Expression</code>, it will be evaluated for
+		 *      each element and the result will be used as the property value
+		 *      for that element.</li>
+		 *  <li>In all other cases, a property value will be treated as a
+		 *      literal and assigned for all elements.</li>
+		 * </ul>
+		 * @param vals an object containing the properties and values to set.
+		 * @param t a transitioner or time span for updating object values. If
+		 *  the input is a transitioner, it will be used to store the updated
+		 *  values. If the input is a number, a new Transitioner with duration
+		 *  set to the input value will be used. The input is null by default,
+		 *  in which case object values are updated immediately.
+		 * @param filter an optional Boolean-valued filter function for
+		 * 	limiting which items are visited
+		 * @return the transitioner used to update the values
+		 */
+		public function setProperties(vals:Object, t:*=null,
+			filter:*=null):Transitioner
+		{
+			var trans:Transitioner = Transitioner.instance(t);
+			var f:Function = Filter.$(filter);
+			for (var name:String in vals)
+				Arrays.setProperty(_list, name, vals[name], f, trans);
+			return trans;
+		}
+		
+		/**
+		 * A function generator that can be used to set properties
+		 * at a later time. This method returns a function that can
+		 * accept a <code>Transitioner</code> as its sole argument and then
+		 * executes the <code>setProperties</code> method. 
+		 * @param vals an object containing the properties and values to set.
+		 *  This is treated the same as the <code>setProperties</code> method.
+		 * @param filter an optional Boolean-valued filter function for
+		 * 	limiting which items are visited
+		 * @return a function that accepts a <code>Transitioner</code> argument
+		 *  and runs <code>setProperties</code>.
+		 */
+		public function setLater(vals:Object, filter:*=null):Function
+		{
+			return function(t:Transitioner=null):Transitioner {
+				return setProperties(vals, t, filter);
+			}
+		}
+		
+		
+		// -- Statistics ------------------------------------------------------
+				
+		/**
+		 * Computes and caches statistics for a data field. The resulting
+		 * <code>Stats</code> object is cached, so that later access does not
+		 * require any re-calculation. The cache of statistics objects may be
+		 * cleared, however, if changes to the data set are made.
+		 * @param field the property name
+		 * @return a <code>Stats</code> object with the computed statistics
+		 */
+		public function stats(field:String):Stats
+		{
+			// TODO: allow custom comparators?
+			
+			// check cache for stats
+			if (_stats[field] != undefined) {
+				return _stats[field] as Stats;
+			} else {
+				return _stats[field] = new Stats(_list, field);
+			}
+		}
+		
+		
+		/**
+		 * Clears any cached stats for the given field. 
+		 * @param field the data field to clear the stats for.
+		 */
+		public function clearStats(field:String):void
+		{
+			delete _stats[field];
+		}
+		
+		
+		// -- Event Dispatcher Methods ----------------------------------------
+		
+		/** @private */
+		protected function fireEvent(type:String, items:*):Boolean
+		{
+			if (_dispatch.hasEventListener(type)) {
+				return _dispatch.dispatchEvent(
+					new DataEvent(type, items, this));
+			}
+			return true;
+		}
+		
+		/** @inheritDoc */
+		public function addEventListener(type:String, listener:Function,
+			useCapture:Boolean=false, priority:int=0, 
+			useWeakReference:Boolean=false) : void
+		{
+			_dispatch.addEventListener(type, listener, useCapture, priority,
+				useWeakReference);
+		}
+		
+		/** @inheritDoc */
+		public function dispatchEvent(event:Event):Boolean
+		{
+			return _dispatch.dispatchEvent(event);
+		}
+		
+		/** @inheritDoc */
+		public function hasEventListener(type:String):Boolean
+		{
+			return _dispatch.hasEventListener(type);
+		}
+		
+		/** @inheritDoc */
+		public function removeEventListener(type:String, listener:Function,
+			useCapture:Boolean=false):void
+		{
+			_dispatch.removeEventListener(type, listener, useCapture);
+		}
+		
+		/** @inheritDoc */
+		public function willTrigger(type:String):Boolean
+		{
+			return _dispatch.willTrigger(type);
+		}
+		
+		// -- Proxy Methods ---------------------------------------------------
+		
+		/** @private */
+		flash_proxy override function getProperty(name:*):*
+		{
+        	return _list[name];
+    	}
+    	
+    	/** @private */
+    	flash_proxy override function setProperty(name:*, value:*):void
+    	{
+    		this.setProperty(name, value);
+    	}
+		
+		/** @private */
+		flash_proxy override function nextNameIndex(idx:int):int
+		{
+			return (idx < _list.length ? idx + 1 : 0);
+		}
+
+		/** @private */
+		flash_proxy override function nextName(idx:int):String
+		{
+			return String(idx-1);
+		}
+		
+		/** @private */
+		flash_proxy override function nextValue(idx:int):*
+		{
+			return _list[idx-1];
+		}
+		
+	} // end of class DataList
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/TreeBuilder.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/TreeBuilder.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/data/TreeBuilder.as	(revision 15)
@@ -0,0 +1,283 @@
+package gssim.gssimstudio.editor.flare.vis.data
+{
+	import gssim.gssimstudio.editor.flare.util.IEvaluable;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.heap.FibonacciHeap;
+	import gssim.gssimstudio.editor.flare.util.heap.HeapNode;
+	
+	import flash.utils.Dictionary;
+
+	/**
+	 * Calculates a spanning tree for a graph structure. This class can
+	 * create spanning trees by breadth-first search, depth-first search, or by
+	 * computing a minimum spanning tree. The default is to find a minimum
+	 * spanning tree, which in turn defaults to breadth-first search if no edge
+	 * weight function is provided.
+	 * 
+	 * <p>This class can annotate graph edges as belonging to the spanning tree
+	 * (done if the <code>annotateEdges</code> property is true), and can
+	 * construct a <code>Tree</code> instance (done if the
+	 * <code>buildTree<code> property is true). Generated <code>Tree<code>
+	 * instances are stored in the <code>tree</code> property. Generated trees
+	 * contain the original nodes and edges in the input graph, and any
+	 * previous parent or child links for input nodes will be cleared and
+	 * overwritten.</p>
+	 * 
+	 * <p>This class is intended as a support class for creating spanning trees
+	 * for <code>flare.vis.data.Data</code> instances. To create annotated
+	 * spanning trees for other purposes, see the
+	 * <code>flare.analytics.graph.SpanningTree</code> class, which provides a
+	 * tree builder that can also be used a visualization operator.</p>
+	 */
+	public class TreeBuilder
+	{
+		/** Policy for a spanning tree built using depth-first search. */
+		public static const DEPTH_FIRST:String   = "depth-first";
+		/** Policy for a spanning tree built using breadth-first search. */
+		public static const BREADTH_FIRST:String = "breadth-first";
+		/** Policy for building a minimum spanning tree. */
+		public static const MINIMUM_SPAN:String  = "minimum-span";
+		
+		private var _s:Property = Property.$("props.spanning");
+		private var _w:Function = null;
+		private var _policy:String = MINIMUM_SPAN;
+		private var _links:int = NodeSprite.GRAPH_LINKS;
+		private var _tree:Tree = null;
+		
+		/** Flag indicating if a spanning tree instance should be created. */
+		public var buildTree:Boolean;
+		/** Flag indicating if edges in the spanning tree should be annotated.
+		 *  If so, the <code>spanningField</code> property will be set for
+		 *  each edge in the graph. */
+		public var annotateEdges:Boolean;
+		
+		/** The tree created by this operator. */
+		public function get tree():Tree { return _tree; }
+		
+		/** The traveral policy used to generate the spanning tree. Should be
+		 *  one of DEPTH_FIRST, BREADTH_FIRST, or MINIMUM_SPAN (default). */
+		public function get policy():String { return _policy; }
+		public function set policy(p:String):void {
+			if (p==DEPTH_FIRST || p==BREADTH_FIRST || p==MINIMUM_SPAN) {
+				_policy = p;
+			} else {
+				throw new Error("Unrecognized policy: "+p);
+			}
+		}
+		
+		/** The property with which to annotate edges that make up the spanning
+		 *  tree. The default value is "props.spanning". This property is used
+		 *  to annotate edges as "true" (if in the spanning forest) or "false"
+		 *  (if not in the spanning forest). */
+		public function get spanningField():String { return _s.name; }
+		public function set spanningField(f:String):void { _s = Property.$(f); }
+		
+		/** The root node for the spanning tree. */
+		public var root:NodeSprite;
+		
+		/** The link type to consider when constructing a spanning tree. Should
+		 *  be one of <code>NodeSprite.GRAPH_LINKS</code>,
+		 *  <code>NodeSprite.IN_LINKS</code>, or
+		 *  <code>NodeSprite.OUT_LINKS</code>. */
+		public function get links():int { return _links; }
+		public function set links(linkType:int):void {
+			if (linkType == NodeSprite.GRAPH_LINKS ||
+				linkType == NodeSprite.IN_LINKS ||
+				linkType == NodeSprite.OUT_LINKS) 
+			{
+				_links = linkType;
+			} else {
+				throw new Error("Unsupported link type: "+linkType);
+			}
+		}
+		
+		/** A function determining edge weights used in the spanning tree
+		 *  calculation. When setting this value, one can pass in either a
+		 *  Function, which should take an EdgeSprite as input and return a
+		 *  Number as output, or a String, in which case the string will be
+		 *  used as a property name from which to retrieve the edge weight
+		 *  value from an EdgeSprite instance. If the value is null (the
+		 *  default) all edges will be assumed to have weight 1.
+		 *  
+		 *  <p><b>NOTE:</b> Edge weights must be greater than or equal to zero!
+		 *  </p> */
+		public function get edgeWeight():Function { return _w; }
+		public function set edgeWeight(w:*):void {
+			if (w==null) {
+				_w = null;
+			} else if (w is String) {
+				_w = Property.$(String(w)).getValue;
+			} else if (w is IEvaluable) {
+				_w = IEvaluable(w).eval;
+			} else if (w is Function) {
+				_w = w;
+			} else {
+				throw new Error("Unrecognized edgeWeight value. " +
+					"The value should be a Function or String.");
+			}
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new SpanningTree operator
+		 * @param policy the spanning tree creation policy. The default is
+		 *  <code>SpanningTree.MINIMUM_SPAN</code>
+		 * @param buildTree if true, this operator will build a new
+		 *  <code>Tree</code> instance containing the spanning tree
+		 * @param annotateEdges if true, this operator will annotate the
+		 *  edges of the original graph as belonging to the spanning tree
+		 * @param root the root node from which to compute the spanning tree
+		 * @param edgeWeight the edge weight values. This can either be a
+		 *  <code>Function</code> that returns weight values or a
+		 *  <code>String</code> providing the name of a property to look up on
+		 *  <code>EdgeSprite</code> instances.
+		 */
+		public function TreeBuilder(policy:String=null,
+			buildTree:Boolean=true, annotateEdges:Boolean=false,
+			root:NodeSprite=null, edgeWeight:*=null)
+		{
+			if (policy) this.policy = policy;
+			this.buildTree = buildTree;
+			this.annotateEdges = annotateEdges;
+			this.root = root;
+			this.edgeWeight = edgeWeight;
+		}
+		
+		/**
+		 * Calculates the spanning tree.
+		 * @param data the data set containing a graph
+		 * @param n the root of the spanning tree
+		 */
+		public function calculate(data:Data, n:NodeSprite):void
+		{
+			var w:Function = edgeWeight;
+			if (n==null) { _tree = null; return; } // do nothing for null root
+			if (!buildTree && !annotateEdges) return; // nothing to do
+			
+			// initialize
+			if (buildTree) {
+				data.nodes.visit(function(nn:NodeSprite):void {
+					nn.removeEdges(NodeSprite.TREE_LINKS);
+				});
+				_tree = new Tree();
+				_tree.root = n;
+			} else {
+				_tree = null;
+			}
+			if (annotateEdges) {
+				data.edges.setProperty(_s.name, false);
+			}
+			
+			switch (_policy) {
+				case DEPTH_FIRST:
+					depthFirstTree(data, n);
+					return;
+				case BREADTH_FIRST:
+					breadthFirstTree(data, n);
+					return;
+				case MINIMUM_SPAN:
+					if (w==null) {
+						breadthFirstTree(data, n);
+					} else {
+						minimumSpanningTree(data, n, w);
+					}
+					return;
+			}
+		}
+		
+		// -- Minimum Spanning Tree -------------------------------------------
+		
+		private function minimumSpanningTree(data:Data, n:NodeSprite, w:Function):void
+		{
+			var hn:HeapNode, weight:Number, e:EdgeSprite;
+			_tree = null;
+			if (buildTree) {
+				_tree = new Tree();
+				_tree.root = n;
+			}
+			
+			// initialize the heap
+			var heap:FibonacciHeap = new FibonacciHeap();
+			data.nodes.visit(function(nn:NodeSprite):void {
+				nn.props.heapNode = heap.insert(nn);
+			});
+			heap.decreaseKey(n.props.heapNode, 0);
+			
+			// collect spanning tree edges (Prim's algorithm)
+			while (!heap.empty) {
+				hn = heap.removeMin();
+				n = hn.data as NodeSprite;
+				// add saved tree edge to spanning tree
+				if ((e=(n.props.treeEdge as EdgeSprite))) {
+					if (annotateEdges) _s.setValue(e, true);
+					if (buildTree) _tree.addChildEdge(e);	
+				}
+				
+				n.visitEdges(function(e:EdgeSprite):void {
+					var nn:NodeSprite = e.other(n);
+					var hnn:HeapNode = nn.props.heapNode;
+					weight = (w==null ? 1 : w(e));
+					if (hnn.inHeap && weight < hnn.key) {
+						nn.props.treeEdge = e; // set tree edge
+						heap.decreaseKey(hnn, weight);
+					}
+				}, _links);
+			}
+			
+			// clean-up nodes
+			data.nodes.visit(function(nn:NodeSprite):void {
+				delete nn.props.treeEdge;
+				delete nn.props.heapNode;
+			});
+		}
+		
+		// -- Breadth-First Traversal -----------------------------------------
+		
+		private function breadthFirstTree(data:Data, n:NodeSprite):void
+		{
+			var visited:Dictionary = buildTree ? null : new Dictionary();
+			
+			var q:Array = [n];
+			while (q.length > 0) {
+				n = q.shift();
+				n.visitEdges(function(e:EdgeSprite):void {
+					var nn:NodeSprite = e.other(n);
+					if (buildTree ? _tree.nodes.contains(nn) : visited[nn])
+						return;
+					if (annotateEdges) _s.setValue(e, true);
+					if (buildTree) {
+						_tree.addChildEdge(e);
+					} else {
+						visited[nn] = true;
+					}
+					q.push(nn);
+				}, _links);
+			}
+		}
+		
+		// -- Depth First Traversal -------------------------------------------
+		
+		private function depthFirstTree(data:Data, n:NodeSprite):void
+		{
+			depthFirstHelper(n, buildTree ? null : new Dictionary());
+		}
+		
+		private function depthFirstHelper(n:NodeSprite, visited:Dictionary):void
+		{
+			n.visitEdges(function(e:EdgeSprite):void {
+				var nn:NodeSprite = e.other(n);
+				if (buildTree ? _tree.nodes.contains(nn) : visited[nn])
+					return;
+				if (annotateEdges) _s.setValue(e, true);
+				if (buildTree) {
+					_tree.addChildEdge(e);
+				} else {
+					visited[nn] = true;
+				}
+				if (nn.degree > 1) depthFirstHelper(nn, visited);
+			}, _links);
+		}
+		
+	} // end of class TreeBuilder
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorList.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorList.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorList.as	(revision 15)
@@ -0,0 +1,187 @@
+package gssim.gssimstudio.editor.flare.vis.operator
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	
+	import flash.utils.flash_proxy;
+	import flash.utils.Proxy;
+	
+	/**
+	 * An OperatorList maintains a sequential chain of operators that are
+	 * invoked one after the other. Operators can be added to an OperatorList
+	 * using the <code>add</code> method. Once added, operators can be
+	 * retrieved and set using their index in the lists, either with array
+	 * notation (<code>[]</code>) or with the <code>getOperatorAt</code> and
+	 * <code>setOperatorAt</code> methods.
+	 */
+	public class OperatorList extends Proxy implements IOperator
+	{
+		// -- Properties ------------------------------------------------------
+		
+		protected var _vis:Visualization;
+		protected var _enabled:Boolean = true;
+		protected var _list:Array = new Array();
+		
+		/** The visualization processed by this operator. */
+		public function get visualization():Visualization { return _vis; }
+		public function set visualization(v:Visualization):void
+		{
+			_vis = v; setup();
+			for each (var op:IOperator in _list) {
+				op.visualization = v;
+			}
+		}
+		
+		/** Indicates if the operator is enabled or disabled. */
+		public function get enabled():Boolean { return _enabled; }
+		public function set enabled(b:Boolean):void { _enabled = b; }
+		
+		/** @inheritDoc */
+		public function set parameters(params:Object):void
+		{
+			Operator.applyParameters(this, params);
+		}
+		
+		/** An array of the operators contained in the operator list. */
+		public function set list(ops:Array):void {
+			// first remove all current operators
+			while (_list.length > 0) {
+				removeOperatorAt(_list.length-1);
+			}
+			// then add the new operators
+			for each (var op:IOperator in ops) {
+				add(op);
+			}
+		}
+		
+		/** The number of operators in the list. */
+		public function get length():uint { return _list.length; }
+		/** Returns the first operator in the list. */
+		public function get first():Object { return _list[0]; }
+		/** Returns the last operator in the list. */
+		public function get last():Object { return _list[_list.length-1]; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new OperatorList.
+		 * @param ops an ordered set of operators to include in the list.
+		 */
+		public function OperatorList(...ops) {
+			for each (var op:IOperator in ops) {
+				add(op);
+			}
+		}
+
+		/** @inheritDoc */
+		public function setup():void
+		{
+			for each (var op:IOperator in _list) {
+				op.setup();
+			}
+		}
+		
+		/**
+		 * Proxy method for retrieving operators from the internal array.
+		 */
+		flash_proxy override function getProperty(name:*):*
+		{
+    		return _list[name];
+    	}
+
+		/**
+		 * Proxy method for setting operators in the internal array.
+		 */
+    	flash_proxy override function setProperty(name:*, value:*):void
+    	{
+        	if (value is IOperator) {
+        		var op:IOperator = IOperator(value);
+        		_list[name] = op;
+        		op.visualization = this.visualization;
+        	} else {
+        		throw new ArgumentError("Input value must be an IOperator.");
+        	}
+    	}
+		
+		/**
+		 * Returns the operator at the specified position in the list
+		 * @param i the index into the operator list
+		 * @return the requested operator
+		 */
+		public function getOperatorAt(i:uint):IOperator
+		{
+			return _list[i];
+		}
+		
+		/**
+		 * Removes the operator at the specified position in the list
+		 * @param i the index into the operator list
+		 * @return the removed operator
+		 */
+		public function removeOperatorAt(i:uint):IOperator
+		{
+			return Arrays.removeAt(_list, i) as IOperator;
+		}
+		
+		/**
+		 * Set the operator at the specified position in the list
+		 * @param i the index into the operator list
+		 * @param op the operator to place in the list
+		 * @return the operator previously at the index
+		 */
+		public function setOperatorAt(i:uint, op:IOperator):IOperator
+		{
+			var old:IOperator = _list[i];
+			op.visualization = visualization;
+			_list[i] = op;
+			return old;
+		}
+		
+		/**
+		 * Adds an operator to the end of this list.
+		 * @param op the operator to add
+		 */
+		public function add(op:IOperator):void
+		{
+			op.visualization = visualization;
+			_list.push(op);
+		}
+		
+		/**
+		 * Removes an operator from this list.
+		 * @param op the operator to remove
+		 * @return true if the operator was found and removed, false otherwise
+		 */
+		public function remove(op:IOperator):Boolean
+		{
+			return Arrays.remove(_list, op) >= 0;
+		}
+		
+		/**
+		 * Removes all operators from this list.
+		 */
+		public function clear():void
+		{
+			Arrays.clear(_list);
+		}
+		
+		/** @inheritDoc */
+		public function operate(t:Transitioner=null):void
+		{
+			t = (t!=null ? t : Transitioner.DEFAULT);
+			for each (var op:IOperator in _list) {
+				if (op.enabled) op.operate(t);
+			}
+		}
+		
+		// -- MXML ------------------------------------------------------------
+		
+		/** @private */
+		public function initialized(document:Object, id:String):void
+		{
+			// do nothing
+		}
+		
+	} // end of class OperatorList
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/Operator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/Operator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/Operator.as	(revision 15)
@@ -0,0 +1,84 @@
+package gssim.gssimstudio.editor.flare.vis.operator
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.IEvaluable;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	
+	/**
+	 * Operators performs processing tasks on the contents of a Visualization.
+	 * These tasks include layout, and color, shape, and size encoding.
+	 * Custom operators can be defined by subclassing this class.
+	 */
+	public class Operator implements IOperator
+	{
+		// -- Properties ------------------------------------------------------
+		
+		private var _vis:Visualization;
+		private var _enabled:Boolean = true;
+		
+		/** The visualization processed by this operator. */
+		public function get visualization():Visualization { return _vis; }
+		public function set visualization(v:Visualization):void {
+			_vis = v; setup();
+		}
+		
+		/** Indicates if the operator is enabled or disabled. */
+		public function get enabled():Boolean { return _enabled; }
+		public function set enabled(b:Boolean):void { _enabled = b; }
+		
+		/** @inheritDoc */
+		public function set parameters(params:Object):void
+		{
+			applyParameters(this, params);
+		}
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Performs an operation over the contents of a visualization.
+		 * @param t a Transitioner instance for collecting value updates.
+		 */
+		public function operate(t:Transitioner=null) : void {
+			// for sub-classes to implement	
+		}
+		
+		/**
+		 * Setup method invoked whenever this operator's visualization
+		 * property is set.
+		 */
+		public function setup():void
+		{
+			// for subclasses
+		}
+		
+		// -- MXML ------------------------------------------------------------
+		
+		/** @private */
+		public function initialized(document:Object, id:String):void
+		{
+			// do nothing
+		}
+		
+		// -- Parameterization ------------------------------------------------
+		
+		/**
+		 * Static method that applies parameter settings to an operator.
+		 * @param op the operator
+		 * @param p the parameter object
+		 */
+		public static function applyParameters(op:IOperator,params:Object):void
+		{
+			if (op==null || params==null) return;
+			var o:Object = op as Object;
+			for (var name:String in params) {
+				var p:Property = Property.$(name);
+				var v:* = params[name];
+				var f:Function = v as Function;
+				if (v is IEvaluable) f = IEvaluable(v).eval;
+				p.setValue(op, f==null ? v : f(op));
+			}
+		}
+		
+	} // end of class Operator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/RandomLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/RandomLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/RandomLayout.as	(revision 15)
@@ -0,0 +1,37 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Layout that places nodes randomly within the layout bounds.
+	 */
+	public class RandomLayout extends Layout
+	{
+		/** The data group to layout. */
+		public var group:String;
+		
+		/**
+		 * Creates a new RandomLayout instance. 
+		 * @param group the data group to layout
+		 */
+		public function RandomLayout(group:String=Data.NODES) {
+			this.group = group;
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+			var r:Rectangle = layoutBounds;
+			visualization.data.visit(function(d:DataSprite):void
+			{
+				var o:Object = _t.$(d);
+				o.x = r.x + r.width * Math.random();
+				o.y = r.y + r.height * Math.random();
+			}, group);
+		}
+		
+	} // end of class RandomLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/CircleLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/CircleLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/CircleLayout.as	(revision 15)
@@ -0,0 +1,270 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.ScaleBinding;
+	
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Layout that places items in a circular layout. This operator is quite
+	 * flexible and offers a number of layout options:
+	 * <ul>
+	 *  <li>By default, all items are arranged along the circumference of the
+	 *      circle using the sort order of the underlying data list.</li>
+	 *  <li>If a data field for either the radius or angle is provided, this
+	 *      layout will act as a radial scatter plot, using the data fields
+	 *      to determine the radius or angle values of the layout.</li>
+	 *  <li>If no data field is provided but the <code>treeLayout</code>
+	 *      property is set to <code>true</code>, the layout will use an
+	 *      underlying tree structure to layout the data. Leaf nodes will be
+	 *      placed along the circumference of the circle, but parent nodes will
+	 *      be placed in the interior. Also, the layout will add spacing to
+	 *      differentiate sibling groups along the circumference.</li>
+	 * </ul>
+	 * 
+	 * <p>The layout also supports mixes of the above modes. For example, if
+	 * <code>treeLayout</code> is set to <code>true</code> and a data field for
+	 * the radius is set, the angles in the layout will be determined as in
+	 * a normal ciruclar tree layout, but the radius values will be derived
+	 * using the data field.</p>
+	 */
+	public class CircleLayout extends Layout
+	{	
+		/** The padding around the circumference of the circle, in pixels. */
+		public var padding:Number = 50;
+		/** The starting angle for the layout, in radians. */
+		public var startAngle:Number = Math.PI / 2;
+		/** The angular width of the layout, in radians (default is 2 pi). */
+		public var angleWidth:Number = 2 * Math.PI;
+		/** Flag indicating if tree structure should inform the layout. */
+		public var treeLayout:Boolean = false;
+		
+		protected var _inner:Number = 0, _innerFrac:Number = NaN;
+		protected var _outer:Number;
+		protected var _group:String;
+		protected var _rField:Property;
+		protected var _aField:Property;
+		protected var _rBinding:ScaleBinding;
+		protected var _aBinding:ScaleBinding;
+		
+		/** The starting (inner) radius at which to place items. 
+		 *  Setting this value also overrides the
+		 *  <code>startRadiusFraction</code> property. */
+		public function get startRadius():Number { return _inner; }
+		public function set startRadius(r:Number):void {
+			_inner = r; _innerFrac = NaN;
+		}
+		
+		/** The starting (inner) radius as a fraction of the outer radius. 
+		 *  Setting this value also overrides the 
+		 *  <code>startRadius</code> property. When this property is set to
+		 *  <code>NaN</code>, the current value of <code>startRadius</code>
+		 *  will be used directly. */
+		public function get startRadiusFraction():Number { return _innerFrac; }
+		public function set startRadiusFraction(f:Number):void {
+			_innerFrac = f;
+		}
+		
+		/** The radius source property. */
+		public function get radiusField():String { return _rBinding.property; }
+		public function set radiusField(f:String):void { _rBinding.property = f; }
+		
+		/** The angle source property. */
+		public function get angleField():String { return _aBinding.property; }
+		public function set angleField(f:String):void { _aBinding.property = f; }
+		
+		/** The scale binding for the radius. */
+		public function get radiusScale():ScaleBinding { return _rBinding; }
+		public function set radiusScale(b:ScaleBinding):void {
+			if (_rBinding) {
+				if (!b.property) b.property = _rBinding.property;
+				if (!b.group) b.group = _rBinding.group;
+				if (!b.data) b.data = _rBinding.data;
+			}
+			_rBinding = b;
+		}
+		
+		/** The scale binding for the angle. */
+		public function get angleScale():ScaleBinding { return _aBinding; }
+		public function set angleScale(b:ScaleBinding):void {
+			if (_aBinding) {
+				if (!b.property) b.property = _aBinding.property;
+				if (!b.group) b.group = _aBinding.group;
+				if (!b.data) b.data = _aBinding.data;
+			}
+			_aBinding = b;
+		}
+		
+		// --------------------------------------------------------------------
+				
+		/**
+		 * Creates a new CircleLayout.
+		 * @param radiusField optional data field to encode as radius length
+		 * @param angleField optional data field to encode as angle
+		 * @param treeLayout boolean flag indicating if any tree-structure in
+		 *  the data should be used to inform the layout
+		 * @param group the data group to process. If tree layout is set to
+		 *  true, this value may get ignored.
+		 */
+		public function CircleLayout(
+			radiusField:String=null, angleField:String=null,
+			treeLayout:Boolean=false, group:String=Data.NODES)
+		{
+			layoutType = POLAR;
+			_group = group;
+			this.treeLayout = treeLayout;
+			
+			_rBinding = new ScaleBinding();
+			_rBinding.group = _group;
+			_rBinding.property = radiusField;
+			
+			_aBinding = new ScaleBinding();
+			_aBinding.group = _group;
+			_aBinding.property = angleField;
+		}
+		
+		/** @inheritDoc */
+		public override function setup():void
+		{
+			if (visualization==null) return;
+			_rBinding.data = visualization.data;
+			_aBinding.data = visualization.data;
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{			
+			var list:DataList = visualization.data.group(_group);
+			var i:int = 0, N:int = list.length, dr:Number;
+			var visitor:Function = null;
+			
+			// determine radius
+			var b:Rectangle = layoutBounds;
+			_outer = Math.min(b.width, b.height)/2 - padding;
+			_inner = isNaN(_innerFrac) ? _inner : _outer * _innerFrac;
+			
+			// set the anchor point
+			var anchor:Point = layoutAnchor;
+			list.visit(function(n:NodeSprite):void { n.origin = anchor; });
+			
+			// compute angles
+			if (_aBinding.property) {
+				// if angle property, get scale binding and do layout
+				_aBinding.updateBinding();
+				_aField = Property.$(_aBinding.property);
+				visitor = function(n:NodeSprite):void {
+					var f:Number = _aBinding.interpolate(_aField.getValue(n));
+					_t.$(n).angle = minAngle(n.angle, 
+					                         startAngle - f*angleWidth);
+				};
+			} else if (treeLayout) {
+				// if tree mode, use tree order
+				setTreeAngles();
+			} else {
+				// if nothing use total sort order
+				i = 0;
+				visitor = function(n:NodeSprite):void {
+					_t.$(n).angle = minAngle(n.angle,
+						                     startAngle - (i/N)*angleWidth);
+					i++;
+				};
+			}
+			if (visitor != null) list.visit(visitor);
+			
+			// compute radii
+			visitor = null;
+			if (_rBinding.property) {
+				// if radius property, get scale binding and do layout
+				_rBinding.updateBinding();
+				_rField = Property.$(_rBinding.property);
+				dr = _outer - _inner;
+				visitor = function(n:NodeSprite):void {
+					var f:Number = _rBinding.interpolate(_rField.getValue(n));
+					_t.$(n).radius = _inner + f * dr;
+				};
+			} else if (treeLayout) {
+				// if tree-mode, use tree depth
+				setTreeRadii();
+			} else {
+				// if nothing, use outer radius
+				visitor = function(n:NodeSprite):void {
+					_t.$(n).radius = _outer;
+				};
+			}
+			if (visitor != null) list.visit(visitor);
+			if (treeLayout) _t.$(visualization.data.tree.root).radius = 0;
+			
+			// finish up
+			updateEdgePoints(_t);
+		}
+		
+		private function setTreeAngles():void
+		{
+			// first pass, determine the angular spacing
+			var root:NodeSprite = visualization.tree.root, p:NodeSprite = null;
+			var leafCount:int = 0, parentCount:int = 0;
+			root.visitTreeDepthFirst(function(n:NodeSprite):void {
+				if (n.childDegree == 0) {
+					if (p != n.parentNode) {
+						p = n.parentNode;
+						++parentCount;
+					}
+					++leafCount;
+				}
+			});
+			var inc:Number = (-angleWidth) / (leafCount + parentCount);
+			var angle:Number = startAngle;
+			
+			// second pass, set the angles
+			root.visitTreeDepthFirst(function(n:NodeSprite):void {
+				var a:Number = 0, b:Number;
+				if (n.childDegree == 0) {
+					if (p != n.parentNode) {
+						p = n.parentNode;
+						angle += inc;
+					}
+					a = angle;
+					angle += inc;
+				} else if (n.parent != null) {
+					a = _t.$(n.firstChildNode).angle;
+					b = _t.$(n.lastChildNode).angle - a;
+					while (b >  Math.PI) b -= 2*Math.PI;
+					while (b < -Math.PI) b += 2*Math.PI;
+					a += b / 2;
+				}
+				_t.$(n).angle = minAngle(n.angle, a);
+			});
+		}
+		
+		private function setTreeRadii():void
+		{
+			var n:NodeSprite;
+			var depth:Number = 0, dr:Number = _outer - _inner;
+			
+			for each (n in visualization.tree.nodes) {
+				if (n.childDegree == 0) {
+					depth = Math.max(n.depth, depth);
+					_t.$(n).radius = _outer;
+				}
+			}
+			for each (n in visualization.tree.nodes) {
+				if (n.childDegree != 0) {
+					_t.$(n).radius = _inner + (n.depth/depth) * dr;
+				}
+			}
+			
+			n = visualization.tree.root;
+			if (!_t.immediate) {
+	        	delete _t._(n).values.radius;
+	        	delete _t._(n).values.angle;
+	        }
+	        _t.$(n).x = n.origin.x;
+	        _t.$(n).y = n.origin.y;
+		}
+		
+	} // end of class CircleLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/DendrogramLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/DendrogramLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/DendrogramLayout.as	(revision 15)
@@ -0,0 +1,160 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.util.Orientation;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	/**
+	 * Layout that places items in a dendrogram for displaying the results of
+	 * hierarchical clustering. This class computes a dendrogram layout and sets
+	 * edge control points to create "U" shaped dendrogram branches. It is
+	 * common, though by no means required, to hide the node instances in a
+	 * dendrogram display.
+	 * 
+	 * <p>To determine the height of dendrogram branches, a distance property
+	 * can be provided. The values of this property will directly determine
+	 * node heights by laying out the depth axis using a linear scale of
+	 * distance values. The distance property should be set for all non-leaf
+	 * nodes in the tree. Typically, leaf nodes have a distance of zero,
+	 * resulting in an aligned list of leaf nodes.</p>
+	 */
+	public class DendrogramLayout extends Layout
+	{
+		// TODO: support axes, too
+		
+		private var _orient:String = Orientation.TOP_TO_BOTTOM; // the orientation of the tree
+		private var _dp:Property;
+		
+		private var _leafCount:int;
+		private var _leafIndex:int = 0;
+		private var _maxDist:Number;
+		private var _b1:Number;
+		private var _db:Number;
+		private var _d1:Number;
+		private var _dd:Number;
+		
+		/** Data property to use as the distance field for
+		 *  determining the height values of dendrogram branches. */
+		public function get distanceProperty():String { return _dp.name; }
+		public function set distanceProperty(dp:String):void {
+			_dp = Property.$(dp);
+		}
+		
+		/** The orientation of the dendrogram */
+		public function get orientation():String { return _orient; }
+		public function set orientation(o:String):void { _orient = o; }
+		
+		/**
+		 * Creates a new DendrogramLayout.
+		 * @param distField data property to use as the distance field for
+		 *  determining the height values of dendrogram branches
+		 * @param orientation the orientation of the dendrogram
+		 */
+		public function DendrogramLayout(distField:String=null,
+			orientation:String=Orientation.TOP_TO_BOTTOM)
+		{
+			_dp = distField==null ? null : Property.$(distField);
+			_orient = orientation;
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+			init();
+			doLayout(visualization.tree.root);
+		}
+		
+		/**
+		 * Initialize the layout.
+		 */
+		private function init():void
+		{
+			var root:NodeSprite = visualization.tree.root;
+			_leafCount = visualization.tree.countLeaves();
+			_leafIndex = 0;
+			_maxDist = _dp!=null ? _dp.getValue(root) : computeHeights(root);
+			
+			switch (_orient) {
+				case Orientation.TOP_TO_BOTTOM:
+					_b1 = layoutBounds.left;
+					_db = layoutBounds.width;
+					_d1 = layoutBounds.bottom;
+					_dd = -layoutBounds.height;
+					break;
+				case Orientation.BOTTOM_TO_TOP:
+					_b1 = layoutBounds.left;
+					_db = layoutBounds.width;
+					_d1 = layoutBounds.top;
+					_dd = layoutBounds.height;
+					break;
+				case Orientation.LEFT_TO_RIGHT:
+					_b1 = layoutBounds.top;
+					_db = layoutBounds.height;
+					_d1 = layoutBounds.right;
+					_dd = -layoutBounds.width;
+					break;
+				case Orientation.RIGHT_TO_LEFT:
+					_b1 = layoutBounds.top;
+					_db = layoutBounds.height;
+					_d1 = layoutBounds.left;
+					_dd = layoutBounds.width;
+					break;
+			}
+		}
+		
+		private function computeHeights(n:NodeSprite):int
+		{
+			n.u = 0;
+			for (var i:int=0; i<n.childDegree; ++i) {
+				n.u = Math.max(n.u, 1 + computeHeights(n.getChildNode(i)));
+			}
+			return n.u;
+		}
+		
+		private function doLayout(n:NodeSprite):Number
+		{
+			var d:Number = _dp!=null ? _dp.getValue(n) : n.u;
+			d = _d1 + _dd * (d / _maxDist);
+			
+			if (n.childDegree > 0) {
+				var b:Number = 0, bc:Number;
+				for (var i:int=0; i<n.childDegree; ++i) {
+					var c:NodeSprite = n.getChildNode(i);
+					b += (bc=doLayout(c));
+					layoutEdge(c.parentEdge, bc, d);
+				}
+				b /= n.childDegree;
+			} else {
+				var step:Number = 1.0 / _leafCount;
+				b = _b1 + _db * step * (0.5 + _leafIndex++);
+			}
+			layoutNode(n, b, d);
+			return b;
+		}
+		
+		private function layoutNode(n:NodeSprite, b:Number, d:Number):void
+		{
+			var o:Object = _t.$(n);
+			if (Orientation.isVertical(_orient)) {
+				o.x = b; o.y = d;
+			} else {
+				o.x = d; o.y = b;
+			}
+		}
+		
+		private function layoutEdge(e:EdgeSprite, b:Number, d:Number):void
+		{
+			var vert:Boolean = Orientation.isVertical(_orient);
+			if (e.points == null) {
+				var s:NodeSprite = e.source;
+				var t:NodeSprite = e.target;
+				e.points = [(s.x+t.x)/2, (s.y+t.y)/2];
+			}
+			_dummy.x = b; b = _dummy.x;
+			_dummy.x = d; d = _dummy.x;
+			_t.$(e).points = vert ? [b, d] : [d, b];
+		}
+		
+	} // end of class DendrogramLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/ForceDirectedLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/ForceDirectedLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/ForceDirectedLayout.as	(revision 15)
@@ -0,0 +1,235 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.physics.Particle;
+	import gssim.gssimstudio.editor.flare.physics.Simulation;
+	import gssim.gssimstudio.editor.flare.physics.Spring;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	/**
+	 * Layout that places nodes based on a physics simulation of
+	 * interacting forces. By default, nodes repel each other, edges act as
+	 * springs, and drag forces (similar to air resistance) are applied. This
+	 * algorithm can be run for multiple iterations for a run-once layout
+	 * computation or repeatedly run in an animated fashion for a dynamic and
+	 * interactive layout (set <code>Visualization.continuousUpdates = true
+	 * </code>).
+	 * 
+	 * <p>The running time of this layout algorithm is the greater of O(N log N)
+	 * and O(E), where N is the number of nodes and E the number of edges.
+	 * The addition of custom forces to the simulation may affect this.</p>
+	 * 
+	 * <p>The force directed layout is implemented using the physics simulator
+	 * provided by the <code>flare.physics</code> package. The
+	 * <code>Simulation</code> used to drive this layout can be set explicitly,
+	 * allowing any number of custom force directed layouts to be created
+	 * through the selection of <code>IForce</code> modules. Each node in the
+	 * layout is mapped to a <code>Particle</code> instance and each edge
+	 * to a <code>Spring</code> in the simulation. Once the simulation has been
+	 * initialized, you can retrieve these instances through the
+	 * <code>node.props.particle</code> and <code>edge.props.spring</code>
+	 * properties, respectively.</p>
+	 * 
+	 * @see flare.physics
+	 */
+	public class ForceDirectedLayout extends Layout
+	{
+		private var _sim:Simulation;
+		private var _step:Number = 1;
+		private var _iter:int = 1;
+		private var _gen:uint = 0;
+		private var _enforceBounds:Boolean = false;
+		
+		// simulation defaults
+		private var _mass:Number = 1;
+		private var _restLength:Number = 30;
+		private var _tension:Number = 0.3;
+		private var _damping:Number = 0.1;
+		
+		/** The default mass value for node/particles. */
+		public function get defaultParticleMass():Number { return _mass; }
+		public function set defaultParticleMass(v:Number):void { _mass = v; }
+		
+		/** The default spring rest length for edge/springs. */
+		public function get defaultSpringLength():Number { return _restLength; }
+		public function set defaultSpringLength(v:Number):void { _restLength = v; }
+		
+		/** The default spring tension for edge/springs. */
+		public function get defaultSpringTension():Number { return _tension; }
+		public function set defaultSpringTension(v:Number):void { _tension = v; }
+		
+		/** The number of iterations to run the simulation per invocation
+		 *  (default is 1, expecting continuous updates). */
+		public function get iterations():int { return _iter; }
+		public function set iterations(iter:int):void { _iter = iter; }
+		
+		/** The number of time ticks to advance the simulation on each
+		 *  iteration (default is 1). */
+		public function get ticksPerIteration():int { return _step; }
+		public function set ticksPerIteration(ticks:int):void { _step = ticks; }
+		
+		/** The physics simulation driving this layout. */
+		public function get simulation():Simulation { return _sim; }
+		
+		/** Flag indicating if the layout bounds should be enforced. 
+		 *  If true, the layoutBounds will limit node placement. */
+		public function get enforceBounds():Boolean { return _enforceBounds; }
+		public function set enforceBounds(b:Boolean):void { _enforceBounds = b; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new ForceDirectedLayout.
+		 * @param iterations the number of iterations to run the simulation
+		 *  per invocation
+		 * @param sim the physics simulation to use for the layout. If null
+		 *  (the default), default simulation settings will be used
+		 */
+		public function ForceDirectedLayout(enforceBounds:Boolean=false, 
+			iterations:int=1, sim:Simulation=null)
+		{
+			_enforceBounds = enforceBounds;
+			_iter = iterations;
+			_sim = (sim==null ? new Simulation(0, 0, 0.1, -10) : sim);
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+			++_gen; // update generation counter
+			init(); // populate simulation
+			
+			// run simulation
+			_sim.bounds = _enforceBounds ? layoutBounds : null;
+			for (var i:uint=0; i<_iter; ++i) {
+				_sim.tick(_step);
+			}
+			visualization.data.nodes.visit(update); // update positions
+			updateEdgePoints(_t);
+		}
+		
+		// -- value transfer --------------------------------------------------
+		
+		/**
+		 * Transfer the physics simulation results to an item's layout.
+		 * @param d a DataSprite
+		 * @return true, to signal a visitor to continue
+		 */
+		protected function update(d:DataSprite):void
+		{
+			var p:Particle = d.props.particle;
+			if (!p.fixed) {
+				var o:Object = _t.$(d);
+				o.x = p.x;
+				o.y = p.y;
+			}
+		}
+		
+		// -- simulation management -------------------------------------------
+		
+		/**
+		 * Initializes the Simulation for this ForceDirectedLayout
+		 */
+		protected function init():void
+		{
+			var data:Data = visualization.data, o:Object;
+			var p:Particle, s:Spring, n:NodeSprite, e:EdgeSprite;
+			
+			// initialize all simulation entries
+			for each (n in data.nodes) {
+				p = n.props.particle;
+				o = _t.$(n);
+				if (p == null) {
+					n.props.particle = (p = _sim.addParticle(_mass, o.x, o.y));
+					p.fixed = o.fixed;
+				} else {
+					p.x = o.x;
+					p.y = o.y;
+					p.fixed = o.fixed;
+				}
+				p.tag = _gen;
+			}
+			for each (e in data.edges) {
+				s = e.props.spring;
+				if (s == null) {
+					e.props.spring = (s = _sim.addSpring(
+						e.source.props.particle, e.target.props.particle,
+						_restLength, _tension, _damping));
+				}
+				s.tag = _gen;
+			}
+			
+			// set up simulation parameters
+			// this needs to be kept separate from the above initialization
+			// to ensure all simulation items are created first
+			if (mass != null) {
+				for each (n in data.nodes) {
+					p = n.props.particle;
+					p.mass = mass(n);
+				}
+			}
+			for each (e in data.edges) {
+				s = e.props.spring;
+				if (restLength != null)
+					s.restLength = restLength(e);
+				if (tension != null)
+					s.tension = tension(e);
+				if (damping != null)
+					s.damping = damping(e);
+			}
+			
+			// clean-up unused items
+			for each (p in _sim.particles)
+				if (p.tag != _gen) p.kill();
+			for each (s in _sim.springs)
+				if (s.tag != _gen) s.kill();
+		}
+		
+		/**
+		 * Function for assigning mass values to particles. By default, this
+		 * simply returns the default mass value. This function can be replaced
+		 * to perform custom mass assignment.
+		 */
+		public var mass:Function = function(d:DataSprite):Number {
+			return _mass;
+		}
+		
+		/**
+		 * Function for assigning rest length values to springs. By default,
+		 * this simply returns the default rest length value. This function can
+		 * be replaced to perform custom rest length assignment.
+		 */
+		public var restLength:Function = function(e:EdgeSprite):Number {
+			return _restLength;
+		}
+		
+		/**
+		 * Function for assigning tension values to springs. By default, this
+		 * method computes spring tension adaptively, based on the connectivity
+		 * of the attached particles, to create more stable layouts. More
+		 * specifically, the tension is computed as the default tension value
+		 * divided by the square root of the maximum degree of the attached
+		 * particles. This function can be replaced to perform custom tension
+		 * assignment.
+		 */
+		public var tension:Function = function(e:EdgeSprite):Number {
+			var s:Spring = Spring(e.props.spring);
+			var n:Number = Math.max(s.p1.degree, s.p2.degree);
+			return _tension / Math.sqrt(n);
+		}
+		
+		/**
+		 * Function for assigning damping constant values to springs. By
+		 * default, this simply uses the spring's computed tension value
+		 * divided by 10. This function can be replaced to perform custom
+		 * damping assignment.
+		 */
+		public var damping:Function = function(e:EdgeSprite):Number {
+			return Spring(e.props.spring).tension / 10;
+		}
+		
+	} // end of class ForceDirectedLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/NodeLinkTreeLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/NodeLinkTreeLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/NodeLinkTreeLayout.as	(revision 15)
@@ -0,0 +1,408 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Orientation;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Layout that places nodes using a tidy layout of a node-link tree
+	 * diagram. This algorithm lays out a rooted tree such that each
+	 * depth level of the tree is on a shared line. The orientation of the
+	 * tree can be set such that the tree goes left-to-right (default),
+	 * right-to-left, top-to-bottom, or bottom-to-top.
+	 * 
+	 * <p>The algorithm used is that of Christoph Buchheim, Michael JÃŒnger,
+	 * and Sebastian Leipert from their research paper
+	 * <a href="http://citeseer.ist.psu.edu/buchheim02improving.html">
+	 * Improving Walker's Algorithm to Run in Linear Time</a>, Graph Drawing 2002.
+	 * This algorithm corrects performance issues in Walker's algorithm, which
+	 * generalizes Reingold and Tilford's method for tidy drawings of trees to
+	 * support trees with an arbitrary number of children at any given node.</p>
+	 */
+	public class NodeLinkTreeLayout extends Layout
+	{
+		// -- Properties ------------------------------------------------------
+		
+		/** Property name for storing parameters for this layout. */
+		public static const PARAMS:String = "nodeLinkTreeLayoutParams";
+		
+		private var _orient:String = Orientation.LEFT_TO_RIGHT; // orientation
+		private var _bspace:Number = 5;  // the spacing between sibling nodes
+    	private var _tspace:Number = 25; // the spacing between subtrees
+    	private var _dspace:Number = 50; // the spacing between depth levels
+    	private var _depths:Array = new Array(20); // stores depth co-ords
+    	private var _maxDepth:int = 0;
+    	private var _ax:Number, _ay:Number; // for holding anchor co-ordinates
+		
+		/** The orientation of the layout. */
+		public function get orientation():String { return _orient; }
+		public function set orientation(o:String):void { _orient = o; }
+		
+		/** The space between successive depth levels of the tree. */
+		public function get depthSpacing():Number { return _dspace; }
+		public function set depthSpacing(s:Number):void { _dspace = s; }
+		
+		/** The space between siblings in the tree. */
+		public function get breadthSpacing():Number { return _bspace; }
+		public function set breadthSpacing(s:Number):void { _bspace = s; }
+		
+		/** The space between different sub-trees. */
+		public function get subtreeSpacing():Number { return _tspace; }
+		public function set subtreeSpacing(s:Number):void { _tspace = s; }
+		
+		
+		// -- Methods ---------------------------------------------------------
+	
+		/**
+		 * Creates a new NodeLinkTreeLayout.
+		 * @param orientation the orientation of the layout
+		 * @param depthSpace the space between depth levels in the tree
+		 * @param breadthSpace the space between siblings in the tree
+		 * @param subtreeSpace the space between different sub-trees
+		 */		
+		public function NodeLinkTreeLayout(
+			orientation:String=Orientation.LEFT_TO_RIGHT, depthSpace:Number=50,
+			breadthSpace:Number=5, subtreeSpace:Number=25)
+		{
+			_orient = orientation;
+			_dspace = depthSpace;
+			_bspace = breadthSpace;
+			_tspace = subtreeSpace;
+		}
+	
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+        	Arrays.fill(_depths, 0);
+        	_maxDepth = 0;
+        	
+        	var root:NodeSprite = layoutRoot as NodeSprite;
+        	if (root == null) { _t = null; return; }
+        	var rp:Params = params(root);
+
+        	firstWalk(root, 0, 1);                       // breadth/depth stats
+        	var a:Point = layoutAnchor;
+        	_ax = a.x; _ay = a.y;                        // determine anchor
+        	determineDepths();                           // sum depth info
+        	secondWalk(root, null, -rp.prelim, 0, true); // assign positions
+        	updateEdgePoints(_t);                        // update edges
+    	}
+
+		protected override function autoAnchor():void
+		{
+			// otherwise generate anchor based on the bounds
+			var b:Rectangle = layoutBounds;
+			var r:NodeSprite = layoutRoot as NodeSprite;
+			switch (_orient) {
+			case Orientation.LEFT_TO_RIGHT:
+				_ax = b.x + _dspace + r.w;
+				_ay = b.y + b.height / 2;
+				break;
+			case Orientation.RIGHT_TO_LEFT:
+				_ax = b.width - (_dspace + r.w);
+				_ay = b.y + b.height / 2;
+				break;
+			case Orientation.TOP_TO_BOTTOM:
+				_ax = b.x + b.width / 2;
+				_ay = b.y + _dspace + r.h;
+				break;
+			case Orientation.BOTTOM_TO_TOP:
+				_ax = b.x + b.width / 2;
+				_ay = b.height - (_dspace + r.h);
+				break;
+			default:
+				throw new Error("Unrecognized orientation value");
+			}
+			_anchor.x = _ax;
+			_anchor.y = _ay;
+		}
+
+    	private function firstWalk(n:NodeSprite, num:int, depth:uint):void
+    	{
+    		setSizes(n);
+    		updateDepths(depth, n);
+    		var np:Params = params(n);
+    		np.number = num;
+    		
+    		var expanded:Boolean = n.expanded;
+    		if (n.childDegree == 0 || !expanded) // is leaf
+    		{
+    			var l:NodeSprite = n.prevNode;
+    			np.prelim = l==null ? 0 : params(l).prelim + spacing(l,n,true);
+    		}
+    		else if (expanded) // has children, is expanded
+    		{
+    			var midpoint:Number, i:uint;
+    			var lefty:NodeSprite = n.firstChildNode;
+    			var right:NodeSprite = n.lastChildNode;
+    			var ancestor:NodeSprite = lefty;
+    			var c:NodeSprite = lefty;
+    			
+    			for (i=0; c != null; ++i, c = c.nextNode) {
+    				firstWalk(c, i, depth+1);
+    				ancestor = apportion(c, ancestor);
+    			}
+    			executeShifts(n);
+    			midpoint = 0.5 * (params(lefty).prelim + params(right).prelim);
+    			
+    			l = n.prevNode;
+    			if (l != null) {
+    				np.prelim = params(l).prelim + spacing(l,n,true);
+    				np.mod = np.prelim - midpoint;
+    			} else {
+    				np.prelim = midpoint;
+    			}
+    		}
+    	}
+    
+    	private function apportion(v:NodeSprite, a:NodeSprite):NodeSprite
+    	{
+    		var w:NodeSprite = v.prevNode;
+    		if (w != null) {
+    			var vip:NodeSprite, vim:NodeSprite, vop:NodeSprite, vom:NodeSprite;
+    			var sip:Number, sim:Number, sop:Number, som:Number;
+    			
+    			vip = vop = v;
+    			vim = w;
+    			vom = vip.parentNode.firstChildNode;
+    			
+    			sip = params(vip).mod;
+    			sop = params(vop).mod;
+    			sim = params(vim).mod;
+    			som = params(vom).mod;
+    			
+    			var shift:Number;
+    			var nr:NodeSprite = nextRight(vim);
+    			var nl:NodeSprite = nextLeft(vip);
+    			while (nr != null && nl != null) {
+    				vim = nr;
+    				vip = nl;
+    				vom = nextLeft(vom);
+    				vop = nextRight(vop);
+    				params(vop).ancestor = v;
+    				shift = (params(vim).prelim + sim) - 
+    					(params(vip).prelim + sip) + spacing(vim,vip,false);
+    				
+    				if (shift > 0) {
+    					moveSubtree(ancestor(vim,v,a), v, shift);
+    					sip += shift;
+    					sop += shift;
+    				}
+    				
+    				sim += params(vim).mod;
+                	sip += params(vip).mod;
+                	som += params(vom).mod;
+                	sop += params(vop).mod;
+                
+                	nr = nextRight(vim);
+                	nl = nextLeft(vip);
+            	}
+            	if (nr != null && nextRight(vop) == null) {
+                	var vopp:Params = params(vop);
+                	vopp.thread = nr;
+                	vopp.mod += sim - sop;
+            	}
+            	if (nl != null && nextLeft(vom) == null) {
+                	var vomp:Params = params(vom);
+                	vomp.thread = nl;
+                	vomp.mod += sip - som;
+                	a = v;
+            	}
+        	}
+        	return a;
+    	}
+    
+    	private function nextLeft(n:NodeSprite):NodeSprite
+    	{
+    		var c:NodeSprite = null;
+        	if (n.expanded) c = n.firstChildNode;
+        	return (c != null ? c : params(n).thread);
+    	}
+
+    	private function nextRight(n:NodeSprite):NodeSprite
+    	{
+    		var c:NodeSprite = null;
+    		if (n.expanded) c = n.lastChildNode;
+        	return (c != null ? c : params(n).thread);
+    	}
+
+		private function moveSubtree(wm:NodeSprite, wp:NodeSprite, shift:Number):void
+		{
+			var wmp:Params = params(wm);
+			var wpp:Params = params(wp);
+			var subtrees:Number = wpp.number - wmp.number;
+			wpp.change -= shift/subtrees;
+			wpp.shift += shift;
+			wmp.change += shift/subtrees;
+			wpp.prelim += shift;
+			wpp.mod += shift;
+		}   
+
+		private function executeShifts(n:NodeSprite):void
+		{
+			var shift:Number = 0, change:Number = 0;
+			for (var c:NodeSprite = n.lastChildNode; c != null; c = c.prevNode)
+			{
+				var cp:Params = params(c);
+				cp.prelim += shift;
+				cp.mod += shift;
+				change += cp.change;
+				shift += cp.shift + change;
+			}
+		}
+		
+		private function ancestor(vim:NodeSprite, v:NodeSprite, a:NodeSprite):NodeSprite
+		{
+			var vimp:Params = params(vim);
+			var p:NodeSprite = v.parentNode;
+			return (vimp.ancestor.parentNode == p ? vimp.ancestor : a);
+		}
+    
+    	private function secondWalk(n:NodeSprite, p:NodeSprite, m:Number, depth:uint, visible:Boolean):void
+    	{
+    		// set position
+    		var np:Params = params(n);
+    		var o:Object = _t.$(n);
+    		setBreadth(o, p, (visible ? np.prelim : 0) + m);
+    		setDepth(o, p, _depths[depth]);
+    		setVisibility(n, o, visible);
+    		
+    		// recurse
+    		var v:Boolean = n.expanded ? visible : false;
+    		var b:Number = m + (n.expanded ? np.mod : np.prelim)
+    		if (v) depth += 1;
+    		for (var c:NodeSprite = n.firstChildNode; c!=null; c=c.nextNode)
+    		{
+    			secondWalk(c, n, b, depth, v);
+    		}
+    		np.clear();
+    	}
+
+		private function setBreadth(n:Object, p:NodeSprite, b:Number):void
+		{
+			switch (_orient) {
+				case Orientation.LEFT_TO_RIGHT:
+				case Orientation.RIGHT_TO_LEFT:
+					n.y = _ay + b;
+					break;
+				case Orientation.TOP_TO_BOTTOM:
+				case Orientation.BOTTOM_TO_TOP:
+					n.x = _ax + b;
+					break;
+				default:
+					throw new Error("Unrecognized orientation value");
+			}
+		}
+
+		private function setDepth(n:Object, p:NodeSprite, d:Number):void
+		{
+			switch (_orient) {
+				case Orientation.LEFT_TO_RIGHT:
+					n.x = _ax + d;
+					break;
+				case Orientation.RIGHT_TO_LEFT:
+					n.x = _ax - d;
+					break;
+				case Orientation.TOP_TO_BOTTOM:
+					n.y = _ay + d;
+					break;
+				case Orientation.BOTTOM_TO_TOP:
+					n.y = _ax - d;
+					break;
+				default:
+					throw new Error("Unrecognized orientation value");
+			}
+		}
+		
+		private function setVisibility(n:NodeSprite, o:Object, visible:Boolean):void
+		{
+    		o.alpha = visible ? 1.0 : 0.0;
+    		o.mouseEnabled = visible;
+    		if (n.parentEdge != null) {
+    			o = _t.$(n.parentEdge);
+    			o.alpha = visible ? 1.0 : 0.0;
+    			o.mouseEnabled = visible;
+    		}
+
+		}
+		
+		private function setSizes(n:NodeSprite):void
+		{
+			_t.endSize(n, _rect);
+			n.w = _rect.width;
+			n.h = _rect.height;
+		}
+		
+		private function spacing(l:NodeSprite, r:NodeSprite, siblings:Boolean):Number
+		{
+			var w:Boolean = Orientation.isVertical(_orient);
+			return (siblings ? _bspace : _tspace) + 0.5 *
+					(w ? l.w + r.w : l.h + r.h)
+    	}
+    
+    	private function updateDepths(depth:uint, item:NodeSprite):void
+    	{
+    		var v:Boolean = Orientation.isVertical(_orient);
+    		var d:Number = v ? item.h : item.w;
+
+			// resize if needed
+			if (depth >= _depths.length) {
+    			_depths = Arrays.copy(_depths, new Array(int(1.5*depth)));
+    			for (var i:int=depth; i<_depths.length; ++i) _depths[i] = 0;
+			} 
+
+        	_depths[depth] = Math.max(_depths[depth], d);
+        	_maxDepth = Math.max(_maxDepth, depth);
+    	}
+    
+    	private function determineDepths():void
+    	{
+        	for (var i:uint=1; i<_maxDepth; ++i)
+            	_depths[i] += _depths[i-1] + _dspace;
+    	}
+		
+		// -- Parameter Access ------------------------------------------------
+		
+		private function params(n:NodeSprite):Params
+		{
+			var p:Params = n.props[PARAMS] as Params;
+			if (p == null) {
+				p = new Params();
+				n.props[PARAMS] = p;
+			}
+			if (p.number == -2) { p.init(n); }
+			return p;
+    	}
+		
+	} // end of class NodeLinkTreeLayout
+
+}
+
+
+import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+
+class Params {
+	public var prelim:Number = 0;
+	public var mod:Number = 0;
+	public var shift:Number = 0;
+	public var change:Number = 0;
+	public var number:int = -2;
+	public var ancestor:NodeSprite = null;
+	public var thread:NodeSprite = null;
+    
+    public function init(item:NodeSprite):void
+    {
+    	ancestor = item;
+    	number = -1;
+    }
+
+	public function clear():void
+	{
+		number = -2;
+		prelim = mod = shift = change = 0;
+		ancestor = thread = null;
+	}
+} // end of class Params
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/AxisLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/AxisLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/AxisLayout.as	(revision 15)
@@ -0,0 +1,217 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.scale.ScaleType;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.axis.CartesianAxes;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.ScaleBinding;
+	
+	/**
+	 * Layout that places items along the X and Y axes according to data
+	 * properties. The AxisLayout can also compute stacked layouts, in which
+	 * elements that share the same data values along an axis are consecutively
+	 * stacked on top of each other.
+	 */
+	public class AxisLayout extends Layout
+	{
+		protected var _xStacks:Boolean = false;
+		protected var _yStacks:Boolean = false;
+		
+		protected var _xField:Property;
+		protected var _yField:Property;
+		protected var _xBinding:ScaleBinding;
+		protected var _yBinding:ScaleBinding;
+		
+		// ------------------------------------------------
+		
+		/** The x-axis source property. */
+		public function get xField():String { return _xBinding.property; }
+		public function set xField(f:String):void { _xBinding.property = f; }
+		
+		/** The y-axis source property. */
+		public function get yField():String { return _yBinding.property; }
+		public function set yField(f:String):void { _yBinding.property = f; }
+		
+		/** Flag indicating if values should be stacked according to their
+		 *  x-axis values. */
+		public function get xStacked():Boolean { return _xStacks; }
+		public function set xStacked(b:Boolean):void { _xStacks = b; }
+
+		/** Flag indicating if values should be stacked according to their
+		 *  y-axis values. */
+		public function get yStacked():Boolean { return _yStacks; }
+		public function set yStacked(b:Boolean):void { _yStacks = b; }
+		
+		/** The scale binding for the x-axis. */
+		public function get xScale():ScaleBinding { return _xBinding; }
+		public function set xScale(b:ScaleBinding):void {
+			if (_xBinding) {
+				if (!b.property) b.property = _xBinding.property;
+				if (!b.group) b.group = _xBinding.group;
+				if (!b.data) b.data = _xBinding.data;
+			}
+			_xBinding = b;
+		}
+		
+		/** The scale binding for the y-axis. */
+		public function get yScale():ScaleBinding { return _yBinding; }
+		public function set yScale(b:ScaleBinding):void {
+			if (_yBinding) {
+				if (!b.property) b.property = _yBinding.property;
+				if (!b.group) b.group = _yBinding.group;
+				if (!b.data) b.data = _yBinding.data;
+			}
+			_yBinding = b;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new AxisLayout
+		 * @param xAxisField the x-axis source property
+		 * @param yAxisField the y-axis source property
+		 * @param xStacked indicates if values should be stacked according to
+		 *  their x-axis values
+		 * @param yStacked indicates if values should be stacked according to
+		 *  their y-axis values
+		 */		
+		public function AxisLayout(xAxisField:String=null, yAxisField:String=null,
+								   xStacked:Boolean=false, yStacked:Boolean=false)
+		{
+			layoutType = CARTESIAN;
+			
+			_xBinding = new ScaleBinding();
+			_xBinding.group = Data.NODES;
+			_xBinding.property = xAxisField;
+			_xStacks = xStacked;
+			
+			_yBinding = new ScaleBinding();
+			_yBinding.group = Data.NODES;
+			_yBinding.property = yAxisField;
+			_yStacks = yStacked;
+		}
+		
+		/** @inheritDoc */
+		public override function setup():void
+		{
+			if (visualization==null) return;
+			_xBinding.data = visualization.data;
+			_yBinding.data = visualization.data;
+			
+			var axes:CartesianAxes = super.xyAxes;
+			axes.xAxis.axisScale = _xBinding;
+			axes.yAxis.axisScale = _yBinding;
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+			_xField = Property.$(_xBinding.property);
+			_yField = Property.$(_yBinding.property);
+			
+			var axes:CartesianAxes = super.xyAxes;
+			_xBinding.updateBinding(); axes.xAxis.axisScale = _xBinding;
+			_yBinding.updateBinding(); axes.yAxis.axisScale = _yBinding;
+			
+			if (_xStacks || _yStacks) { rescale(); }			
+			var x0:Number = axes.originX;
+			var y0:Number = axes.originY;
+
+			var xmapPos:Object = _xStacks ? new Object() : null;
+			var xmapNeg:Object = _xStacks ? new Object() : null;
+			var ymapPos:Object = _yStacks ? new Object() : null;
+			var ymapNeg:Object = _yStacks ? new Object() : null;
+			
+			visualization.data.nodes.visit(function(d:DataSprite):void {
+				var dx:Object, dy:Object, x:Number, y:Number, s:Number, z:Number;
+				var o:Object = _t.$(d);
+				dx = _xField.getValue(d); dy = _yField.getValue(d);
+				
+				var map:Object;
+				if (_xField != null) {
+					x = axes.xAxis.X(dx);
+					if (_xStacks) {
+						map = (dx < 0 ? xmapNeg : xmapPos);
+						z = x - x0;
+						s = z + (isNaN(s=map[dy]) ? 0 : s);
+						o.x = x0 + s;
+						o.w = z;
+						map[dy] = s;
+					} else {
+						o.x = x;
+						o.w = x - x0;
+					}
+				}
+				if (_yField != null) {
+					y = axes.yAxis.Y(dy);
+					if (_yStacks) {
+						map = (dy < 0 ? ymapNeg : ymapPos);
+						z = y - y0;
+						s = z + (isNaN(s=map[dx]) ? 0 : s);
+						o.y = y0 + s;
+						o.h = z;
+						map[dx] = s;
+					} else {
+						o.y = y;
+						o.h = y - y0;
+					}
+				}
+			});
+		}
+		
+		/** @private */
+		protected function rescale():void {
+			var xmapPos:Object = _xStacks ? new Object() : null;
+			var xmapNeg:Object = _xStacks ? new Object() : null;
+			var ymapPos:Object = _yStacks ? new Object() : null;
+			var ymapNeg:Object = _yStacks ? new Object() : null;
+			var xmax:Number = 0;
+			var xmin:Number = 0;
+			var ymax:Number = 0;
+			var ymin:Number = 0;
+			
+			visualization.data.nodes.visit(function(d:DataSprite):void {
+				var x:Object = _xField.getValue(d);
+				var y:Object = _yField.getValue(d);
+				var v:Number;
+				
+				if (_xStacks) {
+					if (x < 0) { 
+						v = isNaN(xmapNeg[y]) ? 0 : xmapNeg[y];
+						xmapNeg[y] = v = (Number(x) + v);
+						if (v < xmin) xmin = v;
+					} else {
+						v = isNaN(xmapPos[y]) ? 0 : xmapPos[y];
+						xmapPos[y] = v = (Number(x) + v);
+						if (v > xmax) xmax = v;
+					}
+				}
+				if (_yStacks) {
+					if (y < 0) {
+						v = isNaN(ymapNeg[x]) ? 0 : ymapNeg[x];
+						ymapNeg[x] = v = (Number(y) + v);
+						if (v < ymin) ymin = v;
+						
+					} else {
+						v = isNaN(ymapPos[x]) ? 0 : ymapPos[x];
+						ymapPos[x] = v = (Number(y) + v);
+						if (v > ymax) ymax = v;
+					}
+				}
+			});
+			
+			if (_xStacks) {
+				_xBinding.scaleType = ScaleType.LINEAR;
+				_xBinding.preferredMin = xmin;
+				_xBinding.preferredMax = xmax;
+			}
+			if (_yStacks) {
+				_yBinding.scaleType = ScaleType.LINEAR;
+				_yBinding.preferredMin = ymin;
+				_yBinding.preferredMax = ymax;
+			}
+		}
+		
+	} // end of class AxisLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/BundledEdgeRouter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/BundledEdgeRouter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/BundledEdgeRouter.as	(revision 15)
@@ -0,0 +1,116 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+
+	/**
+	 * Layout that routes edges in a graph so that they form groups, reducing
+	 * clutter. This operator requires that a tree structure (for example, a
+	 * computed spanning tree) be defined over the graph. The class also sets
+	 * all edges' <code>shape</code> property to <code>Shapes.BSPLINE</code>
+	 * and can optionally compute <code>alpha</code> values to improve edge
+	 * visibility.
+	 * 
+	 * <p>The algorithm uses the tree path between two nodes to define control
+	 * points for routing a b-spline curve. The technique is adapted from
+	 * Danny Holten's work on
+	 * <a href="http://www.win.tue.nl/~dholten/papers/bundles_infovis.pdf">
+	 * Hierarchical Edge Bundles</a>, InfoVis 2006.</p>
+	 */
+	public class BundledEdgeRouter extends Operator
+	{
+		/** Determines how "tight" the edges are bundled. At 0, all edges are
+		 *  unbundled straight lines. At 1, the edges bundle together tightly.
+		 *  The default is 0.85. */
+		public var bundling:Number = 0.85;
+		/** Removes the shared ancestor along a node path. */
+		public var removeSharedAncestor:Boolean = false;
+		
+		/**
+		 * Creates a new BundledEdgeRouter 
+		 * @param bundling the tightness of edge bundles
+		 */
+		public function BundledEdgeRouter(bundling:Number=0.85,
+			removeSharedAncestor:Boolean=false)
+		{
+			this.bundling = bundling;
+			this.removeSharedAncestor = removeSharedAncestor;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			t = (t==null ? Transitioner.DEFAULT : t);
+			
+			var u:NodeSprite, v:NodeSprite, pu:NodeSprite, pv:NodeSprite;
+			var p1:Array = [], p2:Array = [];
+			var d1:int, d2:int, o:Object;
+			var ux:Number, uy:Number, dx:Number, dy:Number;
+			
+			// compute edge bundles
+			for each (var e:EdgeSprite in visualization.data.edges) {
+				u = e.source; p1.push(pu=u); d1 = u.depth;
+				v = e.target; p2.push(pv=v); d2 = v.depth;
+				
+				// trace paths to the least common ancestor of u,v
+				while (d1 > d2) { p1.push(pu=pu.parentNode); --d1; }
+				while (d2 > d1) { p2.push(pv=pv.parentNode); --d2; }
+				while (pu != pv) {
+					p1.push(pu=pu.parentNode);
+					p2.push(pv=pv.parentNode);
+				}
+				
+				// collect b-spline control points
+				var p:Array = t.$(e).points;
+				if (p==null) { p = []; } else { Arrays.clear(p); }
+				
+				d1 = p1.length;
+				d2 = p2.length;
+				if ((d1+d2)==4 && d1>1 && d2>1) { // shared parent
+					addPoint(p, p1[1], t);
+				} else {
+					var off:int = removeSharedAncestor ? 1 : 0;
+					for (var i:int=1; i<p1.length-off; ++i)
+						addPoint(p, p1[i], t);
+					for (i=p2.length-1; --i>=1;)
+						addPoint(p, p2[i], t);
+				}
+				
+				// set the bundling strength by adjusting control points
+				var b:Number = bundling, ib:Number = 1-b, N:int = p.length;
+				if (b < 1) {
+					o = t.$(u); ux = o.x; uy = o.y;
+					o = t.$(v);	dx = o.x; dy = o.y;
+					dx = (dx-ux)/(N+2);
+					dy = (dy-uy)/(N+2);
+
+					for (i=0; i<N; i+=2) {
+						p[i]   = b*p[i]   + ib*(ux + (i+2)*dx);
+						p[i+1] = b*p[i+1] + ib*(uy + (i+2)*dy);
+					}
+				}
+				
+				o = t.$(e);
+				o.points = p;
+				e.shape = Shapes.BSPLINE;
+				
+				// clean-up
+				Arrays.clear(p1);
+				Arrays.clear(p2);
+			}
+		}
+		
+		private static function addPoint(p:Array, d:DataSprite, t:Transitioner):void
+		{
+			var o:Object = t.$(d);
+			p.push(o.x);
+			p.push(o.y);
+		}
+		
+	} // end of class BundledEdgeRouter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/StackedAreaLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/StackedAreaLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/StackedAreaLayout.as	(revision 15)
@@ -0,0 +1,262 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.scale.LinearScale;
+	import gssim.gssimstudio.editor.flare.scale.OrdinalScale;
+	import gssim.gssimstudio.editor.flare.scale.QuantitativeScale;
+	import gssim.gssimstudio.editor.flare.scale.Scale;
+	import gssim.gssimstudio.editor.flare.scale.TimeScale;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.util.Maths;
+	import gssim.gssimstudio.editor.flare.util.Orientation;
+	import gssim.gssimstudio.editor.flare.util.Stats;
+	import gssim.gssimstudio.editor.flare.vis.axis.CartesianAxes;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Layout that consecutively places items on top of each other. The layout
+	 * currently assumes that each column value is available as separate
+	 * properties of individual DataSprites.
+	 */
+	public class StackedAreaLayout extends Layout
+	{
+		// -- Properties ------------------------------------------------------
+		
+		private var _columns:Array;
+    	private var _peaks:Array;
+    	private var _poly:Array;
+		
+		private var _orient:String = Orientation.BOTTOM_TO_TOP;
+		private var _horiz:Boolean = false;
+		private var _top:Boolean = false;
+		private var _initAxes:Boolean = true;
+		
+		private var _normalize:Boolean = false;
+		private var _padding:Number = 0.05;
+		private var _threshold:Number = 1.0;
+		
+		private var _scale:QuantitativeScale = new LinearScale(0,0,10,true);
+		private var _colScale:Scale;
+		
+		/** Array containing the column names. */
+		public function get columns():Array { return _columns; }
+		public function set columns(cols:Array):void {
+			_columns = Arrays.copy(cols);
+			_peaks = new Array(cols.length);
+			_poly = new Array(cols.length);
+			_colScale = getScale(_columns);
+		}
+		
+		/** Flag indicating if the visualization should be normalized. */		
+		public function get normalize():Boolean { return _normalize; }
+		public function set normalize(b:Boolean):void { _normalize = b; }
+		
+		/** Value indicating the padding (as a percentage of the view)
+		 *  that should be reserved within the visualization. */
+		public function get padding():Number { return _padding; }
+		public function set padding(p:Number):void {
+			if (p<0 || isNaN(p) || !isFinite(p)) return;
+			_padding = p;
+		}
+		
+		/** Threshold size value (in pixels) that at least one column width
+		 *  must surpass for a stack to remain visible. */
+		public function get threshold():Number { return _threshold; }
+		public function set threshold(t:Number):void { _threshold = t; }
+		
+		/** The orientation of the layout. */
+		public function get orientation():String { return _orient; }
+		public function set orientation(o:String):void {
+			_orient = o;
+			_horiz = Orientation.isHorizontal(_orient);
+        	_top   = (_orient == Orientation.TOP_TO_BOTTOM ||
+        			  _orient == Orientation.LEFT_TO_RIGHT);
+        	initializeAxes();
+		}
+		
+		/** The scale used to layout the stacked values. */
+		public function get scale():QuantitativeScale { return _scale; }
+		public function set scale(s:QuantitativeScale):void {
+			_scale = s; _scale.dataMin = 0;
+		}
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates a new StackedAreaLayout.
+		 * @param cols an ordered array of properties for the column values
+		 * @param padding percentage of space to leave as a padding margin
+		 *  for the stacked chart
+		 */		
+		public function StackedAreaLayout(cols:Array=null, padding:Number=0.05)
+		{
+			layoutType = CARTESIAN;
+			if (cols != null) this.columns = cols;
+			this.padding = padding;
+		}
+		
+		private static function getScale(cols:Array):Scale
+		{
+			var stats:Stats = new Stats(cols);
+			switch (stats.dataType) {
+				case Stats.NUMBER:
+					return new LinearScale(stats.minimum, stats.maximum, 10, true);
+				case Stats.DATE:
+					return new TimeScale(stats.minDate, stats.maxDate, true);
+				case Stats.OBJECT:
+				default:
+					return new OrdinalScale(stats.distinctValues, true, false);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function setup():void
+		{
+			if (!_initAxes || visualization==null) return;
+			initializeAxes();
+			(_horiz ? xyAxes.yAxis : xyAxes.xAxis).showLines = false;
+		}
+		
+		/**
+		 * Initializes the axes prior to layout.
+		 */
+		protected function initializeAxes():void
+		{
+			if (!_initAxes || visualization==null) return;
+			var axes:CartesianAxes = xyAxes;
+			if (_horiz) {
+				axes.xAxis.axisScale = _scale;
+				axes.yAxis.axisScale = _colScale;
+			} else {
+				axes.xAxis.axisScale = _colScale;
+				axes.yAxis.axisScale = _scale;
+			}
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+	        // get the orientation specifics sorted out
+	        var bounds:Rectangle = layoutBounds;
+	        var hgt:Number, wth:Number;
+	        var xbias:int, ybias:int, sign:int, len:int;
+	        hgt = (_horiz ? bounds.width : bounds.height);
+	        wth = (_horiz ? -bounds.height : bounds.width);
+	        xbias = (_horiz ? 1 : 0);
+	        ybias = (_horiz ? 0 : 1);
+	        sign = _top ? 1 : -1;
+	        len = _columns.length;
+
+	        var minX:Number = _horiz ? bounds.bottom : bounds.left;
+	        var minY:Number = _horiz ? (_top ? bounds.left : bounds.right)
+	                                 : (_top ? bounds.top : bounds.bottom);
+	                                 
+			// perform first walk to get the data distribution
+	        _scale.dataMax = peaks();
+	        initializeAxes();
+	        
+	        // initialize current polygon
+	        var axes:CartesianAxes = super.xyAxes;
+	        var scale:Scale = (_horiz ? axes.yAxis : axes.xAxis).axisScale;
+	        var xx:Number;
+	        for (var j:uint=0; j<len; ++j) {
+				xx = minX + wth * scale.interpolate(_columns[j]);
+	            _poly[2*(len+j)+xbias] = xx;
+	            _poly[2*(len+j)+ybias] = minY;
+	            _poly[2*(len-1-j)+xbias] = xx;
+	            _poly[2*(len-1-j)+ybias] = minY;
+	        }
+	        
+	        // perform second walk to compute polygon layout
+	        visualization.data.nodes.visit(function(d:NodeSprite):void
+	        {
+	        	var obj:Object = _t.$(d);
+	        	var height:Number = 0, i:uint;
+	        	var visible:Boolean = d.visible && d.alpha>0;
+	        	var filtered:Boolean = !obj.visible;
+	        	
+	        	// set full polygon to current baseline
+	            for (i=0; i<len; ++i) {
+	            	_poly[2*(len-1-i)+ybias] = _poly[2*(len+i)+ybias];
+	            }
+	            
+	            // if not visible, flatten on current baseline
+	        	if (!visible || filtered) {
+	        		if (!visible || _t.immediate) {
+	        			// if already hidden, skip transitioner
+	        			d.points = Arrays.copy(_poly, d.points);
+	        		} else {
+	        			// otherwise interpolate the change
+	        			obj.points = Arrays.copy(_poly, d.props.poly);
+	        		}
+	        		return;
+	        	}
+	        	if (d.points == null) d.points = Arrays.copy(_poly);
+	        	
+	        	// if visible, compute the new heights
+	            for (i=0; i<len; ++i) {
+	                var base:int = 2*(len+i), h:Number;
+	                var value:Number = d.data[_columns[i]];
+	                
+	                if (_normalize) {
+	                	_poly[base+ybias] += sign * hgt * Maths.invLinearInterp(value,0,_peaks[i]);
+	                } else {
+	                	_poly[base+ybias] += sign * hgt * _scale.interpolate(value);
+	                }
+	                
+	                h = Math.abs(_poly[2*(len-1-i)+ybias] - _poly[base+ybias]);
+	                if (h > height) height = h;
+	            }
+	            
+	            // if size is beneath threshold, then hide
+	            if (height < _threshold) {
+	            	d.visible = false;
+	            }
+	            
+	            // update data sprite layout
+	            obj.x = 0; obj.y = 0;
+	            if (_t.immediate) {
+	            	d.points = Arrays.copy(_poly, d.points);
+	            } else {
+	            	obj.points = Arrays.copy(_poly, d.props.poly);
+	            }
+	        }, null, true);
+		}
+		
+		private function peaks():Number
+		{
+			var sum:Number = 0;
+	        
+	        // first, compute max value of the current data
+	        Arrays.fill(_peaks, 0);
+	        visualization.data.nodes.visit(function(d:NodeSprite):void {
+	        	if (!d.visible || d.alpha <= 0 || !_t.$(d).visible)
+	        		return;
+	        	
+	        	for (var i:uint=0; i<_columns.length; ++i) {
+	        		var val:Number = d.data[_columns[i]];
+	        		_peaks[i] += val;
+	        		sum += val;
+	        	}
+	        });
+	        var max:Number = Arrays.max(_peaks);
+	        
+	        // update peaks array as needed
+	        // adjust peaks to include padding space
+	        if (!_normalize) {
+	        	Arrays.fill(_peaks, max);
+	            for (var i:uint=0; i<_peaks.length; ++i) {
+	                _peaks[i] += _padding * _peaks[i];
+	            }
+	            max += _padding*max;
+	        }
+	        
+	        // return max range value
+	        if (_normalize) max = 1.0;
+	        if (isNaN(max)) max = 0;
+	        return max;
+		}
+		
+	} // end of class StackedAreaLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/IcicleTreeLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/IcicleTreeLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/IcicleTreeLayout.as	(revision 15)
@@ -0,0 +1,162 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.util.Orientation;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Layout that places nodes in an icicle layout, distributing nodes
+	 * evenly within the display bounds. To get a standard icicle view, set
+	 * the nodes <code>shape</code> property to <code>Shapes.BLOCK</code> and
+	 * hide all edges. By default, this operator will attempt to scale the
+	 * layout to fit within the display bounds. By setting
+	 * <code>fitToBounds</code> false, the current <code>depthSpacing<code>
+	 * will be preserved, allowing the layout to exceed the bounds along
+	 * the depth dimension.
+	 */
+	public class IcicleTreeLayout extends Layout
+	{
+		private var _orient:String = Orientation.TOP_TO_BOTTOM; // orientation
+		private var _dspace:Number = 50; // the spacing between depth levels
+		private var _maxDepth:int = 0;
+		private var _vertical:Boolean = true;
+		
+		/** Indicates if the layout should be scaled to fit in the bounds. */
+		public var fitToBounds:Boolean = true;
+		
+		/** The orientation of the layout. */
+		public function get orientation():String { return _orient; }
+		public function set orientation(o:String):void { _orient = o; }
+		
+		/** The space between successive depth levels of the tree. */
+		public function get depthSpacing():Number { return _dspace; }
+		public function set depthSpacing(s:Number):void { _dspace = s; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new IcicleTreeLayout. 
+		 * @param orientation the orientation of the layout
+		 */
+		public function IcicleTreeLayout(orientation:String=null)
+		{
+			if (orientation) this.orientation = orientation;
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+			// get bounds parameters
+			var root:NodeSprite = layoutRoot as NodeSprite;
+			var b:Rectangle = layoutBounds;
+			var bMin:Number, bMax:Number, dMax:Number, d:Number, dInc:Number;
+			switch (_orient) {
+				case Orientation.LEFT_TO_RIGHT:
+				case Orientation.RIGHT_TO_LEFT:
+					bMin = b.bottom;
+					bMax = b.top;
+					dMax = b.width;
+					_vertical = false;
+					break;
+				case Orientation.TOP_TO_BOTTOM:
+				case Orientation.BOTTOM_TO_TOP:
+					bMin = b.left;
+					bMax = b.right;
+					dMax = b.height;
+					_vertical = true;
+					break;
+				default:
+					throw new Error("Unrecognized orientation value");
+			}
+			switch (_orient) {
+				case Orientation.LEFT_TO_RIGHT:
+					d = b.left; dInc = _dspace; break;
+				case Orientation.TOP_TO_BOTTOM:
+					d = b.top; dInc = _dspace; break;
+				case Orientation.RIGHT_TO_LEFT:
+					d = b.right; dInc = -_dspace; break;
+				case Orientation.BOTTOM_TO_TOP:
+					d = b.bottom; dInc = -_dspace; break;
+				default:
+					throw new Error("Unrecognized orientation value");
+			}
+			
+			// calculate depth and width
+			_maxDepth = 0;
+			firstPass(root, 0);
+			
+			// scale the depth to fit as needed
+			if (fitToBounds && _maxDepth * _dspace > dMax) {
+				dInc *= dMax / (_maxDepth * _dspace);
+			}
+			
+			// perform the layout
+			doLayout(root, bMin, bMax, d, dInc);
+			updateEdgePoints(_t);
+		}
+		
+		private function firstPass(n:NodeSprite, d:int):Number
+		{
+			if (d > _maxDepth) _maxDepth = d;
+			var extent:Number = 0;
+			if (n.childDegree == 0 || !n.expanded) {
+				extent = 1;
+			} else {
+				for (var i:int=0; i<n.childDegree; ++i) {
+					extent += firstPass(n.getChildNode(i), d+1)
+				}	
+			}
+			n.props.icicleWidth = extent;
+			return extent;
+		}
+		
+		private function doLayout(n:NodeSprite, b1:Number, b2:Number,
+			d:Number, dInc:Number):void
+		{
+			var pw:Number = n.props.icicleWidth;
+			var x:Number = b1, w:Number = b2 - b1;
+			
+			if (n.childDegree > 0 && !n.expanded) {
+				n.visitTreeDepthFirst(function(c:NodeSprite):void {
+					update(c, b1 + w/2, b1 + w/2, d+dInc, dInc, false);
+				});
+			} else {
+				for (var i:int=0; i<n.childDegree; ++i) {
+					var c:NodeSprite = n.getChildNode(i);
+					var cw:Number = w * c.props.icicleWidth / pw;
+					doLayout(c, x, x+cw, d+dInc, dInc);
+					x += cw;
+				}
+			}
+			update(n, b1, b2, d, dInc, true);
+		}
+		
+		private function update(n:NodeSprite, b1:Number, b2:Number, 
+			d:Number, dInc:Number, visible:Boolean):void
+		{
+			var o:Object = _t.$(n);
+			if (_vertical) {
+				o.x = (b1 + b2) / 2;
+				o.y = d + dInc / 2;
+				o.u = b1;
+				o.v = d;
+				o.w = b2 - b1;
+				o.h = dInc;
+			} else {
+				o.x = d + dInc / 2;
+				o.y = (b1 + b2) / 2;
+				o.u = d;
+				o.v = b1;
+				o.w = dInc;
+				o.h = b2 - b1;
+			}
+			var alpha:Number = visible ? 1 : 0;
+			o.alpha = alpha;
+			o.mouseEnabled = visible;
+			if (n.parentEdge != null)
+				_t.$(n.parentEdge).alpha = alpha;
+		}
+		
+	} // end of class IcicleTreeLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/IndentedTreeLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/IndentedTreeLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/IndentedTreeLayout.as	(revision 15)
@@ -0,0 +1,98 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import flash.geom.Point;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	
+	/**
+	 * Layout that places tree nodes in an indented outline layout.
+	 */
+	public class IndentedTreeLayout extends Layout
+	{		
+		private var _bspace:Number = 5;  // the spacing between sibling nodes
+    	private var _dspace:Number = 50; // the spacing between depth levels
+    	private var _depths:Array = new Array(20); // TODO make sure array regrows as needed
+    	private var _maxDepth:int = 0;
+    	private var _ax:Number, _ay:Number; // for holding anchor co-ordinates
+		
+		/** The spacing to use between depth levels (the amount of indent). */
+		public function get depthSpacing():Number { return _dspace; }
+		public function set depthSpacing(s:Number):void { _dspace = s; }
+		
+		/** The spacing to use between rows in the layout. */
+		public function get breadthSpacing():Number { return _bspace; }
+		public function set breadthSpacing(s:Number):void { _bspace = s; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new IndentedTreeLayout.
+		 * @param depthSpace the amount of indent between depth levels
+		 * @param breadthSpace the amount of spacing between rows
+		 */		
+		public function IndentedTreeLayout(depthSpace:Number=50,
+										   breadthSpace:Number=5)
+		{
+			_bspace = breadthSpace;
+			_dspace = depthSpace;
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+        	Arrays.fill(_depths, 0);
+        	_maxDepth = 0;
+        
+        	var a:Point = layoutAnchor;
+        	_ax = a.x + layoutBounds.x;
+        	_ay = a.y + layoutBounds.y;
+        
+        	var root:NodeSprite = layoutRoot as NodeSprite;
+        	if (root == null) return; // TODO: throw exception?
+        	
+        	layoutNode(root,0,0,true);
+    	}
+    	
+    	
+    	private function layoutNode(node:NodeSprite, height:Number, indent:uint, visible:Boolean):Number
+    	{
+    		var x:Number = _ax + indent * _dspace;
+    		var y:Number = _ay + height;
+    		var o:Object = _t.$(node);
+    		node.h = _t.endSize(node, _rect).height;
+    		
+    		// update node
+    		o.x = x;
+    		o.y = y;
+    		o.alpha = visible ? 1.0 : 0.0;
+    		
+    		// update edge
+    		if (node.parentEdge != null) 
+    		{
+    			var e:EdgeSprite = node.parentEdge;
+    			var p:NodeSprite = node.parentNode;
+    			o = _t.$(e); 
+    			o.alpha = visible ? 1.0 : 0.0;
+    			if (e.points == null) {
+					e.points = [(p.x+node.x)/2, (p.y+node.y)/2];
+    			}
+    			o.points = [_t.getValue(p,"x"), y];
+    		}
+    		
+    		if (visible) { height += node.h + _bspace; }
+    		if (!node.expanded) { visible = false; }
+    		
+    		if (node.childDegree > 0) // is not a leaf node
+    		{    			
+    			var c:NodeSprite = node.firstChildNode;   			
+    			for (; c != null; c = c.nextNode) {
+    				height = layoutNode(c, height, indent+1, visible);
+    			}
+    		}
+    		return height;
+    	}
+    	
+	} // end of class IndentedTreeLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/RadialTreeLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/RadialTreeLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/RadialTreeLayout.as	(revision 15)
@@ -0,0 +1,352 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Layout that places tree nodes in a radial layout, laying out depths of a tree
+	 * along circles of increasing radius. 
+	 * This layout can be used for both node-link diagrams, where nodes are
+	 * connected by edges, and for radial space-filling ("sunburst") diagrams.
+	 * To generate space-filling layouts, nodes should have their shape
+	 * property set to <code>Shapes.WEDGE</code> and the layout instance should
+	 * have the <code>useNodeSize<code> property set to false.
+	 * 
+	 * <p>The algorithm used is an adaptation of a technique by Ka-Ping Yee,
+	 * Danyel Fisher, Rachna Dhamija, and Marti Hearst, published in the paper
+	 * <a href="http://citeseer.ist.psu.edu/448292.html">Animated Exploration of
+	 * Dynamic Graphs with Radial Layout</a>, InfoVis 2001. This algorithm computes
+	 * a radial layout which factors in possible variation in sizes, and maintains
+	 * both orientation and ordering constraints to facilitate smooth and
+	 * understandable transitions between layout configurations.
+	 * </p>
+	 */
+	public class RadialTreeLayout extends Layout
+	{
+		// -- Properties ------------------------------------------------------
+		
+		/** Property name for storing parameters for this layout. */
+		public static const PARAMS:String = "radialTreeLayoutParams";
+		/** The default radius increment between depth levels. */
+		public static const DEFAULT_RADIUS:int = 50;
+	
+	    private var _maxDepth:int = 0;
+	    private var _radiusInc:Number = DEFAULT_RADIUS;
+	    private var _theta1:Number = Math.PI/2;
+	    private var _theta2:Number = Math.PI/2 - 2*Math.PI;
+	    private var _sortAngles:Boolean = true;
+	    private var _setTheta:Boolean = false;
+	    private var _autoScale:Boolean = true;
+	    private var _useNodeSize:Boolean = true;
+	    private var _prevRoot:NodeSprite = null;
+
+		/** The radius increment between depth levels. */
+		public function get radiusIncrement():Number { return _radiusInc; }
+		public function set radiusIncrement(r:Number):void { _radiusInc = r; }
+		
+		/** Flag determining if nodes should be sorted by angles to help
+		 *  maintain ordering across different spanning-tree configurations.
+		 *  This sorting is important for understandable transitions when using
+		 *  a radial layout of a general graph. However, it is unnecessary for
+		 *  tree structures and increases the running time of layout. */
+		public function get sortAngles():Boolean { return _sortAngles; }
+		public function set sortAngles(b:Boolean):void { _sortAngles = b; }
+		
+		/** Flag indicating if the layout should automatically be scaled to
+		 *  fit within the layout bounds. */
+		public function get autoScale():Boolean { return _autoScale; }
+		public function set autoScale(b:Boolean):void { _autoScale = b; }
+		
+		/** The initial angle for the radial layout (in radians). */
+		public function get startAngle():Number { return _theta1; }
+		public function set startAngle(a:Number):void {
+			_theta2 += (a - _theta1);
+			_theta1 = a;
+			_setTheta = true;
+		}
+		
+		/** The angular width of the layout (in radians, default is 2 pi). */
+		public function get angleWidth():Number { return _theta1 - _theta2; }
+		public function set angleWidth(w:Number):void {
+			_theta2 = _theta1 - w;
+			_setTheta = true;
+		}
+
+		/** Flag indicating if node's <code>size</code> property should be
+		 *  used to determine layout spacing. If a space-filling radial
+		 *  layout is desired, this value must be false for the layout
+		 *  to be accurate. */
+		public function get useNodeSize():Boolean { return _useNodeSize; }
+		public function set useNodeSize(b:Boolean):void {
+			_useNodeSize = b;
+		}
+
+		// -- Methods ---------------------------------------------------------
+
+		/**
+		 * Creates a new RadialTreeLayout.
+		 * @param radius the radius increment between depth levels
+		 * @param sortAngles flag indicating if nodes should be sorted by angle
+		 *  to maintain node ordering across spanning-tree configurations
+		 * @param autoScale flag indicating if the layout should automatically
+		 *  be scaled to fit within the layout bounds
+		 */		
+		public function RadialTreeLayout(radius:Number=DEFAULT_RADIUS,
+			sortAngles:Boolean=true, autoScale:Boolean=true)
+		{
+			layoutType = POLAR;
+			_radiusInc = radius;
+			_sortAngles = sortAngles;
+			_autoScale = autoScale;
+		}
+
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+			var n:NodeSprite = layoutRoot as NodeSprite;
+			if (n == null) { _t = null; return; }
+			var np:Params = params(n);
+			
+			// calc relative widths and maximum tree depth
+        	// performs one pass over the tree
+        	_maxDepth = 0;
+        	calcAngularWidth(n, 0);
+			
+			if (_autoScale) setScale(layoutBounds);
+			if (!_setTheta) calcAngularBounds(n);
+			_anchor = layoutAnchor;
+			
+			// perform the layout
+	        if (_maxDepth > 0) {
+	        	doLayout(n, _radiusInc, _theta1, _theta2);
+	        } else if (n.childDegree > 0) {
+	        	n.visitTreeDepthFirst(function(n:NodeSprite):void {
+	        		n.origin = _anchor;
+	        		var o:Object = _t.$(n);
+	        		// collapse to inner radius
+					o.radius = o.h = o.v = _radiusInc / 2;
+					o.alpha = 0;
+					o.mouseEnabled = false;
+					if (n.parentEdge != null)
+						_t.$(n.parentEdge).alpha = false;
+            	});
+	        }
+	        
+	        // update properties of the root node
+	        np.angle = _theta2 - _theta1;
+	        n.origin = _anchor;
+	        update(n, 0, _theta1+np.angle/2, np.angle, true);
+	        if (!_t.immediate) {
+	        	delete _t._(n).values.radius;
+	        	delete _t._(n).values.angle;
+	        }
+	        _t.$(n).x = _anchor.x;
+	        _t.$(n).y = _anchor.y;
+			
+			updateEdgePoints(_t);
+		}
+		
+		private function setScale(bounds:Rectangle):void
+		{
+	        var r:Number = Math.min(bounds.width, bounds.height)/2.0;
+	        if (_maxDepth > 0) _radiusInc = r / _maxDepth;
+	    }
+		
+	    /**
+	     * Calculates the angular bounds of the layout, attempting to
+	     * preserve the angular orientation of the display across transitions.
+	     */
+	    private function calcAngularBounds(r:NodeSprite):void
+	    {
+	        if (_prevRoot == null || r == _prevRoot)
+	        {
+	            _prevRoot = r; return;
+	        }
+	        
+	        // try to find previous parent of root
+	        var p:NodeSprite = _prevRoot, pp:NodeSprite;
+	        while (true) {
+	        	pp = p.parentNode;
+	            if (pp == r) {
+	                break;
+	            } else if (pp == null) {
+	                _prevRoot = r;
+	                return;
+	            }
+	            p = pp;
+	        }
+	
+	        // compute offset due to children's angular width
+	        var dt:Number = 0;
+	        
+	        for each (var n:NodeSprite in sortedChildren(r)) {
+	        	if (n == p) break;
+	        	dt += params(n).width;
+	        }
+	        
+	        var rw:Number = params(r).width;
+	        var pw:Number = params(p).width;
+	        dt = -2*Math.PI * (dt+pw/2)/rw;
+	
+	        // set angular bounds
+	        _theta1 = dt + Math.atan2(p.y-r.y, p.x-r.x);
+	        _theta2 = _theta1 + 2*Math.PI;
+	        _prevRoot = r;     
+	    }
+		
+		/**
+	     * Computes relative measures of the angular widths of each
+	     * expanded subtree. Node diameters are taken into account
+	     * to improve space allocation for variable-sized nodes.
+	     * 
+	     * This method also updates the base angle value for nodes 
+	     * to ensure proper ordering of nodes.
+	     */
+	    private function calcAngularWidth(n:NodeSprite, d:int):Number
+	    {
+	        if (d > _maxDepth) _maxDepth = d;       
+	        var aw:Number = 0, diameter:Number = 0;
+	        if (_useNodeSize && d > 0) {
+	        	//diameter = 1;
+	        	diameter = n.expanded && n.childDegree > 0 ? 0 : _t.$(n).size;
+	        } else if (d > 0) {
+	        	var w:Number = n.width, h:Number = n.height;
+	        	diameter = Math.sqrt(w*w+h*h)/d;
+	        	if (isNaN(diameter)) diameter = 0;
+	        }
+
+	        if (n.expanded && n.childDegree > 0) {
+	        	for (var c:NodeSprite=n.firstChildNode; c!=null; c=c.nextNode)
+	        	{
+	        		aw += calcAngularWidth(c, d+1);
+	        	}
+	        	aw = Math.max(diameter, aw);
+	        } else {
+	        	aw = diameter;
+	        }
+			params(n).width = aw;
+	        return aw;
+	    }
+		
+		private static function normalize(angle:Number):Number
+		{
+	        while (angle > 2*Math.PI)
+	            angle -= 2*Math.PI;
+	        while (angle < 0)
+	            angle += 2*Math.PI;
+	        return angle;
+	    }
+
+		private function sortedChildren(n:NodeSprite):Array
+		{
+			var cc:int = n.childDegree;
+			if (cc == 0) return Arrays.EMPTY;
+			var angles:Array = new Array(cc);
+	        
+	        if (_sortAngles) {
+	        	// update base angle for node ordering			
+				var base:Number = -_theta1;
+				var p:NodeSprite = n.parentNode;
+	        	if (p != null) base = normalize(Math.atan2(p.y-n.y, n.x-p.x));
+	        	
+	        	// collect the angles
+	        	var c:NodeSprite = n.firstChildNode;
+		        for (var i:uint=0; i<cc; ++i, c=c.nextNode) {
+		        	angles[i] = normalize(-base + Math.atan2(c.y-n.y,n.x-c.x));
+		        }
+		        // get array of indices, sorted by angle
+		        angles = angles.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY);
+		        // switch in the actual nodes and return
+		        for (i=0; i<cc; ++i) {
+		        	angles[i] = n.getChildNode(angles[i]);
+		        }
+		    } else {
+		    	for (i=0; i<cc; ++i) {
+		        	angles[i] = n.getChildNode(i);
+		        }
+		    }
+	        
+	        return angles;
+	    }
+		
+		/**
+	     * Compute the layout.
+	     * @param n the root of the current subtree under consideration
+	     * @param r the radius, current distance from the center
+	     * @param theta1 the start (in radians) of this subtree's angular region
+	     * @param theta2 the end (in radians) of this subtree's angular region
+	     */
+	    private function doLayout(n:NodeSprite, r:Number,
+	    	theta1:Number, theta2:Number):void
+	    {
+	    	var dtheta:Number = theta2 - theta1;
+	    	var dtheta2:Number = dtheta / 2.0;
+	    	var width:Number = params(n).width;
+	    	var cfrac:Number, nfrac:Number = 0;
+	        
+	        for each (var c:NodeSprite in sortedChildren(n)) {
+	        	var cp:Params = params(c);
+	            cfrac = cp.width / width;
+	            if (c.expanded && c.childDegree > 0)
+	            {
+	                doLayout(c, r+_radiusInc, theta1 + nfrac*dtheta, 
+	                                          theta1 + (nfrac+cfrac)*dtheta);
+	            }
+	            else if (c.childDegree > 0)
+	            {
+	            	var cr:Number = r + _radiusInc;
+	            	var ca:Number = theta1 + nfrac*dtheta + cfrac*dtheta2;
+	            	
+	            	c.visitTreeDepthFirst(function(n:NodeSprite):void {
+	            		n.origin = _anchor;
+	            		update(n, cr, minAngle(n.angle, ca), 0, false);
+	            	});
+	            }
+	            
+	            c.origin = _anchor;
+	            var a:Number = minAngle(c.angle, theta1 + nfrac*dtheta + cfrac*dtheta2);
+	            cp.angle = cfrac * dtheta;
+	            update(c, r, a, cp.angle, true);
+	            nfrac += cfrac;
+	        }
+	    }
+		
+		private function update(n:NodeSprite, r:Number, a:Number,
+								aw:Number, v:Boolean) : void
+		{
+			var o:Object = _t.$(n), alpha:Number = v ? 1 : 0;
+			o.radius = r;
+			o.angle = a;
+			if (aw == 0) {
+				o.h = o.v = r - _radiusInc/2;
+			} else {
+				o.h = r + _radiusInc/2;
+				o.v = r - _radiusInc/2;
+			}
+			o.w = aw;
+			o.u = a - aw/2;
+			o.alpha = alpha;
+			o.mouseEnabled = v;
+			if (n.parentEdge != null)
+				_t.$(n.parentEdge).alpha = alpha;
+		}
+				
+		private function params(n:NodeSprite):Params
+		{
+			var p:Params = n.props[PARAMS];
+			if (p == null) {
+				p = new Params();
+				n.props[PARAMS] = p;
+			}
+			return p;
+		}
+		
+	} // end of class RadialTreeLayout
+}
+
+class Params {
+	public var width:Number = 0;
+	public var angle:Number = 0;
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/PieLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/PieLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/PieLayout.as	(revision 15)
@@ -0,0 +1,86 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Layout that places wedges for pie and donut charts. In addition to
+	 * the layout, this operator updates each node to have a "wedge" shape.
+	 */
+	public class PieLayout extends Layout
+	{
+		private var _field:Property;
+		
+		/** The source property determining wedge size. */
+		public function get source():String { return _field.name; }
+		public function set source(f:String):void { _field = Property.$(f); }
+
+		/** The data group to layout. */
+		public var group:String = Data.NODES;
+		
+		/** The radius of the pie/donut chart. If this value is not a number
+		 *  (NaN) the radius will be determined from the layout bounds. */
+		public var radius:Number = NaN;		
+		/** The width of wedges, negative for a full pie slice. */
+		public var width:Number = -1;
+		/** The initial angle for the pie layout (in radians). */
+		public var startAngle:Number = Math.PI/2;
+		/** The total angular size of the layout (in radians, default 2 pi). */
+		public var angleWidth:Number = 2*Math.PI;
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new PieLayout
+		 * @param field the source data field for determining wedge size
+		 * @param width the radial width of wedges, negative for full slices
+		 */		
+		public function PieLayout(field:String=null, width:Number=-1,
+								  group:String=Data.NODES)
+		{
+			layoutType = POLAR;
+			this.group = group;
+			this.width = width;
+			_field = (field==null) ? null : new Property(field);
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+			var b:Rectangle = layoutBounds;
+			var r:Number = isNaN(radius) ? Math.min(b.width, b.height)/2 : radius;
+			var a:Number = startAngle, aw:Number;
+			var list:DataList = visualization.data.group(group);
+			var sum:Number = list.stats(_field.name).sum;
+			var anchor:Point = layoutAnchor;
+			
+			list.visit(function(d:DataSprite):void {
+				var aw:Number = -angleWidth * (_field.getValue(d)/sum);
+				var rh:Number = (width < 0 ? 0 : width) * r;
+				var o:Object = _t.$(d);
+				
+				d.origin = anchor;
+				
+				//o.angle = a + aw/2;  // angular mid-point
+				//o.radius = (r+rh)/2; // radial mid-point
+				o.x = 0;
+				o.y = 0;
+				
+				o.u = a;  // starting angle
+				o.w = aw; // angle width
+				o.h = r;  // outer radius
+				o.v = rh; // inner radius
+				o.shape = Shapes.WEDGE;
+
+				a += aw;
+			});
+		}
+		
+	} // end of class PieLayout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/TreeMapLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/TreeMapLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/TreeMapLayout.as	(revision 15)
@@ -0,0 +1,283 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Layout that places node in a TreeMap layout that optimizes for low
+	 * aspect ratios of visualized tree nodes. TreeMaps are a form of
+	 * space-filling layout that represents nodes as boxes on the display, with
+	 * children nodes represented as boxes placed within their parent's box.
+	 * This layout determines the area of nodes in the tree map by looking up
+	 * the <code>sizeField</code> property on leaf nodes. By default, this
+	 * property is "size", such that the layout will look for size
+	 * values in the <code>DataSprite.size</code> property.
+	 * 
+	 * <p>
+	 * This particular algorithm is taken from Bruls, D.M., C. Huizing, and 
+	 * J.J. van Wijk, "Squarified Treemaps" In <i>Data Visualization 2000, 
+	 * Proceedings of the Joint Eurographics and IEEE TCVG Sumposium on 
+	 * Visualization</i>, 2000, pp. 33-42. Available online at:
+	 * <a href="http://www.win.tue.nl/~vanwijk/stm.pdf">
+	 * http://www.win.tue.nl/~vanwijk/stm.pdf</a>.
+	 * </p>
+	 * <p>
+	 * For more information on TreeMaps in general, see 
+	 * <a href="http://www.cs.umd.edu/hcil/treemap-history/">
+	 * http://www.cs.umd.edu/hcil/treemap-history/</a>.
+	 * </p>
+	 */
+	public class TreeMapLayout extends Layout
+	{
+		private static const AREA:String = "treeMapArea";
+		
+		private var _kids:Array = new Array();
+		private var _row:Array  = new Array();
+		private var _r:Rectangle = new Rectangle();
+		
+		private var _size:Property = Property.$("size");
+		
+		/** The property from which to access size values for leaf nodes. */
+		public function get sizeField():String { return _size.name; }
+		public function set sizeField(s:String):void { _size = Property.$(s); }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new TreeMapLayout 
+		 * @param sizeField the data property from which to access the size
+		 *  value for leaf nodes. The default is the "size" property.
+		 */
+		public function TreeMapLayout(sizeField:String="size") {
+			this.sizeField = sizeField;
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+	        // setup
+	        var root:NodeSprite = layoutRoot as NodeSprite;
+	        var b:Rectangle = layoutBounds;
+	        _r.x=b.x; _r.y=b.y; _r.width=b.width-1; _r.height=b.height-1;
+	        
+	        // process size values
+	        computeAreas(root);
+	        
+	        // layout root node
+	        var o:Object = _t.$(root);
+	        o.x = 0;//_r.x + _r.width/2;
+	        o.y = 0;//_r.y + _r.height/2;
+	        o.u = _r.x;
+	        o.v = _r.y;
+	        o.w = _r.width;
+	        o.h = _r.height;
+	
+	        // layout the tree
+	        updateArea(root, _r);
+	        doLayout(root, _r);
+		}
+		
+	    /**
+    	 * Compute the pixel areas of nodes based on their size values.
+	     */
+	    private function computeAreas(root:NodeSprite):void
+	    {
+	    	var leafCount:int = 0;
+        
+	        // reset all sizes to zero
+	        root.visitTreeDepthFirst(function(n:NodeSprite):void {
+	        	n.props[AREA] = 0;
+	        });
+        
+	        // set raw sizes, compute leaf count
+	        root.visitTreeDepthFirst(function(n:NodeSprite):void {
+	        	if (n.childDegree == 0) {
+	        		var sz:Number = _size.getValue(_t.$(n));
+	        		n.props[AREA] = sz;
+	        		var p:NodeSprite = n.parentNode;
+	        		for (; p != null; p=p.parentNode)
+	        			p.props[AREA] += sz;
+	        		++leafCount;
+	        	}
+	        });
+        
+	        // scale sizes by display area factor
+	        var b:Rectangle = layoutBounds;
+	        var area:Number = (b.width-1)*(b.height-1);
+	        var scale:Number = area / root.props[AREA];
+	        root.visitTreeDepthFirst(function(n:NodeSprite):void {
+	        	n.props[AREA] *= scale;
+	        });
+	    }
+	    
+	    /**
+	     * Compute the tree map layout.
+	     */
+	    private function doLayout(p:NodeSprite, r:Rectangle):void
+	    {
+	        // create sorted list of children's properties
+	        for (var i:uint = 0; i < p.childDegree; ++i) {
+	        	_kids.push(p.getChildNode(i).props);
+	        }
+	        _kids.sortOn(AREA, Array.NUMERIC);
+	        // update array to point to sprites, not props
+	        for (i = 0; i < _kids.length; ++i) {
+	        	_kids[i] = _kids[i].self;
+	        }
+	        
+	        // do squarified layout of siblings
+	        var w:Number = Math.min(r.width, r.height);
+	        squarify(_kids, _row, w, r); 
+	        _kids.splice(0, _kids.length); // clear _kids
+	        
+	        // recurse
+	        for (i=0; i<p.childDegree; ++i) {
+	        	var c:NodeSprite = p.getChildNode(i);
+	        	if (c.childDegree > 0) {
+	        		updateArea(c, r);
+	        		doLayout(c, r);
+	        	}
+	        }
+	    }
+	    
+	    private function updateArea(n:NodeSprite, r:Rectangle):void
+	    {
+	    	var o:Object = _t.$(n);
+			r.x = o.u;
+			r.y = o.v;
+			r.width = o.w;
+			r.height = o.h;
+			return;
+			
+			/*
+	        Rectangle2D b = n.getBounds();
+	        if ( m_frame == 0.0 ) {
+	            // if no framing, simply update bounding rectangle
+	            r.setRect(b);
+	            return;
+	        }
+	        
+	        // compute area loss due to frame
+	        double dA = 2*m_frame*(b.getWidth()+b.getHeight()-2*m_frame);
+	        double A = n.getDouble(AREA) - dA;
+	        
+	        // compute renormalization factor
+	        double s = 0;
+	        Iterator childIter = n.children();
+	        while ( childIter.hasNext() )
+	            s += ((NodeItem)childIter.next()).getDouble(AREA);
+	        double t = A/s;
+	        
+	        // re-normalize children areas
+	        childIter = n.children();
+	        while ( childIter.hasNext() ) {
+	            NodeItem c = (NodeItem)childIter.next();
+	            c.setDouble(AREA, c.getDouble(AREA)*t);
+	        }
+	        
+	        // set bounding rectangle and return
+	        r.setRect(b.getX()+m_frame,       b.getY()+m_frame, 
+	                  b.getWidth()-2*m_frame, b.getHeight()-2*m_frame);
+	        return;
+	        */
+	    }
+	    
+	    private function squarify(c:Array, row:Array, w:Number, r:Rectangle):void
+	    {
+	    	var worst:Number = Number.MAX_VALUE, nworst:Number;
+	    	var len:int;
+	        
+	        while ((len=c.length) > 0) {
+	            // add item to the row list, ignore if negative area
+	            var item:NodeSprite = c[len-1];
+				var a:Number = item.props[AREA];
+	            if (a <= 0.0) {
+	            	c.pop();
+	                continue;
+	            }
+	            row.push(item);
+	            
+	            nworst = getWorst(row, w);
+	            if (nworst <= worst) {
+	            	c.pop();
+	                worst = nworst;
+	            } else {
+	            	row.pop(); // remove the latest addition
+	                r = layoutRow(row, w, r); // layout the current row
+	                w = Math.min(r.width, r.height); // recompute w
+	                row.splice(0, row.length); // clear the row
+	                worst = Number.MAX_VALUE;
+	            }
+	        }
+	        if (row.length > 0) {
+	            r = layoutRow(row, w, r); // layout the current row
+	            row.splice(0, row.length); // clear the row
+	        }
+	    }
+	
+	    private function getWorst(rlist:Array, w:Number):Number
+	    {
+	    	var rmax:Number = Number.MIN_VALUE;
+	    	var rmin:Number = Number.MAX_VALUE;
+	    	var s:Number = 0;
+
+			for each (var n:NodeSprite in rlist) {
+				var r:Number = n.props[AREA];
+				rmin = Math.min(rmin, r);
+				rmax = Math.max(rmax, r);
+				s += r;
+			}
+	        s = s*s; w = w*w;
+	        return Math.max(w*rmax/s, s/(w*rmin));
+	    }
+	    
+	    private function layoutRow(row:Array, ww:Number, r:Rectangle):Rectangle
+	    {
+	    	var s:Number = 0; // sum of row areas
+	        for each (var n:NodeSprite in row) {
+	        	s += n.props[AREA];
+	        }
+			
+			var xx:Number = r.x, yy:Number = r.y, d:Number = 0;
+			var hh:Number = ww==0 ? 0 : s/ww;
+			var horiz:Boolean = (ww == r.width);
+	        
+	        // set node positions and dimensions
+	        for each (n in row) {
+	        	var p:NodeSprite = n.parentNode;
+	        	var nw:Number = n.props[AREA]/hh;
+	        	
+	        	var o:Object = _t.$(n);
+				if (horiz) {
+	        		o.u = xx + d;
+	        		o.v = yy;
+	        		o.w = nw;
+	        		o.h = hh;
+	        		//o.x = xx + d + nw/2;
+	        		//o.y = yy + hh/2;
+	        	} else {
+	        		o.u = xx;
+	        		o.v = yy + d;
+	        		o.w = hh;
+	        		o.h = nw;
+	        		//o.x = xx + hh/2;
+	        		//o.y = yy + d + nw/2;
+	        	}
+	        	o.x = 0;
+	        	o.y = 0;
+	        	d += nw;
+	        }
+	        
+	        // update space available in rectangle r
+	        if (horiz) {
+	        	r.x = xx; r.y = yy+hh; r.height -= hh;
+	        } else {
+	        	r.x = xx+hh; r.y = yy; r.width -= hh;
+	        }
+	        return r;
+	    }
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/CirclePackingLayout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/CirclePackingLayout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/CirclePackingLayout.as	(revision 15)
@@ -0,0 +1,369 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	import gssim.gssimstudio.editor.flare.util.Sort;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.render.ShapeRenderer;
+	
+	import flash.geom.Rectangle;
+
+	/**
+	 * Layout that places nodes as circles compacted into a larger circle.
+	 * 
+	 * <p>Circle sizes are determined by a node's <code>size</code> property.
+	 * It is assumed that the sizes are set <i>before</i> this operator is run,
+	 * for example, by placing a <code>SizeEncoder</code> prior to this layout
+	 * in an operator list.</p>
+	 * 
+	 * <p>If the <code>treeLayout</code> property is <code>false</code>, all
+	 * nodes will be treated the same and the result will be a "bubble" chart.
+	 * If the <code>treeLayout<code> property is <code>true<code>, circles will
+	 * be nested inside each other according to the tree structure of the data.
+	 * </p>
+	 * 
+	 * <p>The results of this layout can vary dramatically based on the sort
+	 * order of the nodes. For example, sorting the nodes by the
+	 * <code>size</code> property (in either ascending or descending order)
+	 * can result in much cleaner layouts. Use the <code>sort</code> property
+	 * of this class to set a preferred sorting routine. By default, this
+	 * operator will not perform any sorting.</p>
+	 * 
+	 * <p>NOTE: This operator will set a node's <code>renderer</code> and
+	 * <code>shape</code> properties, overriding any previous values.</p>
+	 * 
+	 * <p>The algorithm used to perform the circle packing is adapted from
+	 * W. Wang, H. Wang, G. Dai, and H. Wang's <a
+	 * href="http://portal.acm.org/citation.cfm?id=1124772.1124851">
+	 * Visualization of large hierarchical data by circle packing</a>,
+	 * ACM CHI 2006.</p>
+	 */
+	public class CirclePackingLayout extends Layout
+	{
+		private var _sort:Sort = null;
+		private var _order:int;
+		private var _b:Rectangle = new Rectangle();
+		
+		/** The data group to process. This setting will be ignored if tree mode
+		 *  is set to true. */
+		public var group:String = Data.NODES;
+		
+		/** The amount of spacing between neighboring circles.
+		 *  The default value is 4 pixels. */
+		public var spacing:Number = 4;
+		
+		/** Indicates if the view should be scaled to fit within the
+		 *  display bounds. The default is true. */
+		public var fitInBounds:Boolean = true;
+		
+		/** Indicates if a tree layout (circles nested within circles) should
+		 *  be computed. The default is false. Any data group settings will
+		 *  be ignored if this operator uses a tree layout. */
+		public var treeLayout:Boolean = false;
+		
+		/** A sort criteria for ordering nodes in this layout.
+		 *  Ordered nodes are placed in a spiral starting at the center.
+		 *  The default is null, meaning no sorting is performed. */
+		public function get sort():Sort { return _sort; }
+		public function set sort(s:*):void {
+			_sort = s==null ? s : (s is Sort ? Sort(s) : new Sort(s));
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new CirclePackingLayout.
+		 * @param spacing the minimum spacing between neighboring circles
+		 * @param treeLayout if true, a hierarchical circles-within-circles
+		 *  layout will be peformed; if false (the default) all nodes will be
+		 *  considered equally
+		 * @param sort a sort criteria for ordering nodes in the layout.
+		 *  Ordered nodes are placed in a spiral starting at the center.
+		 */
+		public function CirclePackingLayout(spacing:Number=4,
+			treeLayout:Boolean=false, sort:*=null)
+		{
+			this.spacing = spacing;
+			this.treeLayout = treeLayout;
+			this.sort = sort;
+		}
+		
+		/** @inheritDoc */
+		protected override function layout():void
+		{
+			_order = 0;
+			
+			var data:Data = visualization.data;
+			data.nodes.setProperty("shape", Shapes.CIRCLE, _t);
+			data.nodes.setProperty("renderer", ShapeRenderer.instance, _t);
+			
+			// determine layout anchor from bounds
+			var bounds:Rectangle = layoutBounds;
+			_anchor.x = (bounds.left + bounds.right) / 2;
+			_anchor.y = (bounds.top + bounds.bottom) / 2;
+
+			// compute the circle packing(s)
+			var radius:Number;			
+			if (treeLayout) {
+				// perform hierarchial tree layout
+				var root:NodeSprite = layoutRoot as NodeSprite;
+				var cn:ChainNode = getChainNode(root); cn.x = 0; cn.y = 0;
+				
+				if (root.childDegree > 0) {
+					radius = (cn.r = packTree(root));
+					_t.$(root).size = radius / ShapeRenderer.instance.defaultSize;
+				}
+				shiftTree(root, cn.x, cn.y);
+			} else {
+				// perform flat layout
+				var list:Array = []; data.group(group).visit(list.push);
+				if (_sort) _sort.sort(list);
+				for (var i:int=0; i<list.length; ++i)
+					list[i] = getChainNode(list[i]);
+				radius = packCircle(list, list.length);
+			}
+			
+			var dr:Number = Math.max(2*radius/bounds.width, 2*radius/bounds.height);
+			var scale:Number = fitInBounds ? 0.99/dr : 1;
+			
+			if (treeLayout) {
+				// recurse through the tree
+				layoutHelper(root, _anchor.x, _anchor.y, scale);
+			} else {
+				// layout all circles directly
+				for each (var n:NodeSprite in visualization.data.group(group)) {	
+					cn = n.props.chainNode;
+					update(n, _anchor.x + scale*cn.x,
+					          _anchor.y + scale*cn.y, scale, 1);
+					delete n.props.chainNode;
+				}
+			}
+			updateEdgePoints(_t);
+		}
+		
+		/** Performs layout for tree structures. */
+		private function layoutHelper(n:NodeSprite, xc:Number, yc:Number, scale:Number):void
+		{
+			var cn:ChainNode = n.props.chainNode;
+			var x:Number = xc + scale*cn.x;
+			var y:Number = yc + scale*cn.y;
+			update(n, x, y, scale, 1);
+			delete n.props.chainNode;
+			
+			if (n.childDegree > 0) {
+				if (n.expanded) {
+					for (var i:int=0; i<n.childDegree; ++i)
+						layoutHelper(n.getChildNode(i), xc, yc, scale);
+				} else {
+					for (i=0; i<n.childDegree; ++i)
+						n.getChildNode(i).visitTreeDepthFirst(
+							function(n:NodeSprite):void {
+								update(n, x, y, 0, 0);
+							}
+						);
+				}
+			}
+		}
+		
+		/** Set the final position, size, and visibility */
+		private function update(n:NodeSprite, x:Number, y:Number, scale:Number, alpha:Number):void
+		{
+			var o:Object = _t.$(n);
+			o.x = x;
+			o.y = y;
+			o.size *= scale;
+			o.alpha = alpha;
+			if (treeLayout && n.parentEdge) _t.$(n.parentEdge).alpha = alpha;
+		}
+		
+		/** Shift sub-tree coordinate spaces into correct configuration. */
+		private function shiftTree(n:NodeSprite, nx:Number, ny:Number):void
+		{
+			for (var i:int=0; i<n.childDegree; ++i) {
+				var c:NodeSprite = n.getChildNode(i);
+				var cn:ChainNode = c.props.chainNode;
+				cn.x += nx;
+				cn.y += ny;
+				if (c.childDegree > 0 && c.expanded)
+					shiftTree(c, cn.x, cn.y);
+			}
+		}
+		
+		/** Perform hierarchical circle packing */
+		private function packTree(n:NodeSprite):Number
+		{
+			// do a post-order traversal, so recurse first
+			var r:Number, list:Array = [];
+			for (var i:int=0; i<n.childDegree; ++i) {
+				var c:NodeSprite = n.getChildNode(i);
+				if (c.childDegree > 0 && c.expanded) {
+					r = packTree(c) / ShapeRenderer.instance.defaultSize;
+					_t.$(c).size = r;
+				}
+				list.push(c);
+			}
+			// now sort the child list and perform circle packing
+			if (_sort) _sort.sort(list);
+			for (i=0; i<list.length; ++i)
+				list[i] = getChainNode(list[i]);
+			return packCircle(list, list.length);
+		}
+		
+		/** Pack a set of circles together */
+		private function packCircle(nodes:Array, N:int):Number
+		{
+			var a:ChainNode, b:ChainNode, c:ChainNode, j:ChainNode, k:ChainNode;
+			
+			// initialize bounds and order
+			_b.left  = _b.top    = Number.MAX_VALUE;
+			_b.right = _b.bottom = Number.MIN_VALUE;
+			_order = 0;
+			
+			// create first node
+			a = nodes[0]; a.x = -a.r; a.y = 0; updateBounds(a,_b);
+			if (N==1) return center(nodes, _b);
+			
+			// create second node
+			b = nodes[1]; b.x = b.r; b.y = 0; updateBounds(b,_b);
+			if (N==2) return center(nodes, _b);
+			
+			// create third node build chain
+			c = nodes[2]; place(a, b, c); updateBounds(c,_b);
+			a.insert(c); a.prev = c; c.insert(b); b = a.next;
+			
+			// now iterate through the rest
+			for (var i:int=3; i<N; ++i) {
+				place(a, b, c=nodes[i]);
+				
+				// search for an intersection with a circle on the chain
+				// search in both directions and keep the nearest hit
+				var isect:int = 0, s1:int = 1, s2:int = 1;
+				for (j=b.next; j!=b; j=j.next, ++s1) // forward search
+					if (intersects(j, c)) {
+						isect = 1;
+						break;
+					}
+				if (isect == 1) { // backward search
+					for (k=a.prev; k!=j.prev; k=k.prev, ++s2) 
+						if (intersects(k, c)) {
+							if (s2 < s1) { isect = -1; j = k; }
+							break;
+						}
+				}
+				
+				// update node chain
+				if (isect == 0) {
+					a.insert(c); b = c;
+					updateBounds(c, _b);
+				} else if (isect > 0) {
+					a.splice(j); b = j; --i;
+				} else if (isect < 0) {
+					j.splice(b); a = j; --i;
+				}
+			}
+			
+			// return the radius that encompasses the data
+			return center(nodes, _b);
+		}
+		
+		/** Re-center a group of circles and return the encompassing radius. */
+		private function center(nodes:Array, b:Rectangle):Number
+		{
+			var cx:Number = (b.left + b.right) / 2;
+			var cy:Number = (b.top + b.bottom) / 2;
+			var cr:Number = 0, r:Number;
+			
+			for each (var cn:ChainNode in nodes) {
+				cn.x -= cx;
+				cn.y -= cy;
+				r = cn.r + Math.sqrt(cn.x*cn.x + cn.y*cn.y);
+				if (r > cr) cr = r;
+			}
+			return cr;
+		}
+		
+		/** Update the bounding box around the circles. */
+		private static function updateBounds(c:ChainNode, b:Rectangle):void
+		{
+			if (c.x-c.r < b.left)   b.left   = c.x-c.r;
+			if (c.x+c.r > b.right)  b.right  = c.x+c.r;
+			if (c.y-c.r < b.top)    b.top    = c.y-c.r;
+			if (c.y+c.r > b.bottom) b.bottom = c.y+c.r;
+		}
+		
+		/** Create and initialize a ChainNode to represent the given node.  */
+		private function getChainNode(n:NodeSprite):ChainNode
+		{
+			var cn:ChainNode, r:Number, size:Number = _t.$(n).size;
+			r = spacing/2 + (size * ShapeRenderer.instance.defaultSize);
+			n.props.chainNode = (cn = new ChainNode(r));
+			n.props.order = _order++;
+			return cn;
+		}
+		
+		/** Check for intersection between circles. */
+		private static function intersects(a:ChainNode, b:ChainNode):Boolean
+		{
+			var dx:Number = b.x - a.x;
+			var dy:Number = b.y - a.y;
+			var dr:Number = a.r + b.r;
+			return (dx*dx + dy*dy) < dr*dr - 0.001; // within epsilon
+		}
+		
+		/** Position circle c based on tangency to circles a and b. */
+		private static function place(a:ChainNode, b:ChainNode,
+			c:ChainNode):void
+		{
+			var da:Number = b.r + c.r;                // distance from b to c
+			var db:Number = a.r + c.r;                // distance from a to c
+			var dx:Number = (b.x - a.x);
+			var dy:Number = (b.y - a.y);
+			var dc:Number = Math.sqrt(dx*dx + dy*dy); // distance from a to b
+			dx /= dc; dy /= dc;              // normalize directional vectors
+			
+			// apply law of cosines to get angle at vertex a
+			var cosA:Number = (db*db + dc*dc - da*da) / (2*db*dc);
+			var A:Number = Math.acos(cosA);
+			
+			// compute coordinates based on right triangle relations
+			var x:Number = cosA * db;
+			var h:Number = Math.sin(A) * db;
+			c.x = (a.x + x*dx) + h*dy;
+			c.y = (a.y + x*dy) - h*dx;
+		}
+		
+	} // end of class CirclePackingLayout
+}
+	
+class ChainNode
+{
+	public var r:Number;
+	public var x:Number;
+	public var y:Number;
+	public var next:ChainNode;
+	public var prev:ChainNode;
+	
+	public function get dist():Number {
+		return x*x + y*y;
+	}
+	
+	public function ChainNode(radius:Number) {
+		r = radius;
+		next = prev = this;
+	}
+	
+	public function insert(c:ChainNode):void
+	{
+		var b:ChainNode = next;
+		next = c;
+		c.prev = this;
+		c.next = b;
+		b.prev = c;
+	}
+	
+	public function splice(j:ChainNode):void
+	{
+		next = j;
+		j.prev = this;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/Layout.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/Layout.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/layout/Layout.as	(revision 15)
@@ -0,0 +1,270 @@
+package gssim.gssimstudio.editor.flare.vis.operator.layout
+{
+	import gssim.gssimstudio.editor.flare.animate.TransitionEvent;
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	import gssim.gssimstudio.editor.flare.vis.axis.Axes;
+	import gssim.gssimstudio.editor.flare.vis.axis.CartesianAxes;
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+	
+	import flash.display.Shape;
+	import flash.events.Event;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+
+	/**
+	 * Base class for all operators that perform spatial layout. Provides
+	 * methods for retrieving the desired layout bounds, providing a layout
+	 * anchor point, and returning the layout root (for tree layouts in
+	 * particular). This class also provides convenience methods for
+	 * manipulating the visibility of axes and performing common updates
+	 * to edge control points in graph/tree visualizations.
+	 */
+	public class Layout extends Operator
+	{
+		/** Constant indicating Cartesian (x, y) coordinates. */
+		public static const CARTESIAN:String = "cartesian";
+		/** Constant indicating polar (radius, angle) coordinates. */
+		public static const POLAR:String = "polar";
+		
+		/** @private */
+		protected static const _dummy:Shape = new Shape();
+		/** @private */
+		protected static const _rect:Rectangle = new Rectangle();
+		
+		// -- Properties ------------------------------------------------------
+				
+		/** The type of layout and axes. This value should be
+		 *  <code>CARTESIAN</code> for x,y axes, <code>POLAR</code> for polar
+		 *  coordinates (radius, angle), or null for no axes. */
+		public var layoutType:String = null;
+		
+		/** A transitioner for storing value updates. */
+		protected var _t:Transitioner = null;
+		
+		protected var _anchor:Point = new Point(0,0);
+		protected var _setAnchor:Boolean = false;
+		
+		private var _bounds:Rectangle = null;
+		private var _root:DataSprite = null;
+		
+		/** The layout bounds for the layout. If this value is not explicitly
+		 *  set, the bounds for the visualization is returned. */
+		public function get layoutBounds():Rectangle {
+			if (_bounds != null) return _bounds;
+			if (visualization != null) return visualization.bounds;
+			return null;
+		}
+		public function set layoutBounds(b:Rectangle):void { _bounds = b; }
+		
+		/** The layout anchor, used by some layout instances to place an
+		 *  initial item or determine a focal point. */
+		public function get layoutAnchor():Point {
+			if (!_setAnchor)
+				autoAnchor();
+			return _anchor;
+		}
+		public function set layoutAnchor(p:Point):void {
+			_anchor = p;
+			_setAnchor = true;
+		}
+		
+		/** Automatically-generate an anchor point. */
+		protected function autoAnchor():void
+		{
+			if (layoutType == POLAR) {
+				var b:Rectangle = layoutBounds;
+				_anchor.x = (b.left + b.right) / 2;
+				_anchor.y = (b.top + b.bottom) / 2;
+			} else {
+				_anchor.x = 0;
+				_anchor.y = 0;
+			}
+		}
+		
+		/** The layout root, the root node for tree layouts. */
+		public function get layoutRoot():DataSprite {
+			if (_root != null) return _root;
+			if (visualization != null) {
+				return visualization.data.tree.root;
+			}
+			return null;
+		}
+		public function set layoutRoot(r:DataSprite):void { _root = r; }
+		
+				
+		// -- Placement and Axis Helpers --------------------------------------
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			_t = (t ? t : Transitioner.DEFAULT);
+			adjustAxes();
+			layout();
+			_t = null;
+		}
+		
+		/**
+		 * Calculates the spatial layout of visualized items. Layout operators
+		 * override this method with their layout implementations.
+		 * @param t a Transitioner instance for collecting value updates.
+		 */
+		protected function layout():void
+		{
+			// sub-classes should override
+		}
+		
+		/** @private */
+		protected function adjustAxes():void
+		{
+			if (layoutType == CARTESIAN) {
+				showAxes(_t);
+			} else {
+				hideAxes(_t);
+			}
+		}
+		
+		/**
+		 * Reveals the axes.
+		 * @param t a transitioner to collect value updates
+		 * @return the input transitioner
+		 */
+		public function showAxes(t:Transitioner=null):Transitioner
+		{
+			var axes:Axes = visualization.axes;
+			if (axes == null || axes.visible) return t;
+			
+			if (t==null || t.immediate) {
+				axes.alpha = 1;
+				axes.visible = true;
+			} else {
+				t.$(axes).alpha = 1;
+				t.$(axes).visible = true;
+			}
+			return t;
+		}
+		
+		/**
+		 * Hides the axes.
+		 * @param t a transitioner to collect value updates
+		 * @return the input transitioner
+		 */
+		public function hideAxes(t:Transitioner=null):Transitioner
+		{
+			var axes:Axes = visualization.axes;
+			if (axes == null || !axes.visible) return t;
+			
+			if (t==null || t.immediate) {
+				axes.alpha = 0;
+				axes.visible = false;
+			} else {
+				t.$(axes).alpha = 0;
+				t.$(axes).visible = false;
+			}
+			return t;
+		}
+		
+		/**
+		 * Returns the visualization's axes as a CartesianAxes instance.
+		 * Creates/modifies existing axes as needed to ensure the
+		 * presence of CartesianAxes.
+		 */
+		protected function get xyAxes():CartesianAxes
+		{
+			var vis:Visualization = visualization;
+			if (vis == null) return null;
+			
+			if (vis.xyAxes == null) {
+				vis.axes = new CartesianAxes();
+			}
+			return vis.xyAxes;
+		}
+		
+		/**
+		 * Returns an angle value that minimizes the angular distance
+		 * between a reference angle and a target angle. This
+		 * method may shift the angle value by multiples of 2 pi.
+		 * @param a1 the reference angle to stay close to
+		 * @param a2 the target angle value
+		 * @return an angle that minimizes the distance
+		 */
+	    protected function minAngle(a1:Number, a2:Number):Number
+		{
+			var inc:Number = 2*Math.PI*(a1 > a2 ? 1 : -1);
+			for (; Math.abs(a1-a2) > Math.PI; a2 += inc) null;
+			return a2;
+		}
+		
+		// -- Edge Helpers ----------------------------------------------------
+		
+		private static var _clear:Boolean;
+		
+		/**
+		 * Updates all edges to be straight lines. Useful for undoing the
+		 * results of layouts that route edges using edge control points.
+		 * @param list a data list of edges to straighten
+		 * @param t a transitioner to collect value updates
+		 */
+		public static function straightenEdges(list:DataList,
+			t:Transitioner):Transitioner
+		{
+			// set end points to mid-points
+			list.visit(function(e:EdgeSprite):void {
+				if (e.points == null) return;
+				_clear = true;
+				
+				var src:NodeSprite = e.source;
+				var trg:NodeSprite = e.target;
+				
+				// create new control points
+				var i:uint, len:uint = e.points.length, f:Number;
+				var cp:Array = new Array(len);
+				var x1:Number, y1:Number, x2:Number, y2:Number;
+				
+				// get target end points
+				x1 = t.$(src).x; y1 = t.$(src).y;
+				x2 = t.$(trg).x; y2 = t.$(trg).y;
+				
+				for (i=0; i<len; i+=2) {
+					f = (i+2)/(len+2);
+					cp[i]   = x1 + f * (x2 - x1);
+					cp[i+1] = y1 + f * (y2 - y1);
+				}
+				t.$(e).points = cp;
+			});
+			return t;
+		}
+		
+		/** @private */
+		protected function updateEdgePoints(t:Transitioner=null):void
+		{
+			if (t==null || t.immediate || layoutType==POLAR) {
+				clearEdgePoints();
+			} else {
+				_clear = false;
+				straightenEdges(visualization.data.edges, t);
+				// after transition, clear out control points
+				if (_clear) {
+					var f:Function = function(evt:Event):void {
+						clearEdgePoints();
+						t.removeEventListener(TransitionEvent.END, f);
+					};
+					t.addEventListener(TransitionEvent.END, f);
+				}
+			}
+		}
+		
+		/**
+		 * Strips all EdgeSprites in a visualization of any control points.
+		 */
+		public function clearEdgePoints():void
+		{
+			visualization.data.edges["points"] = null;
+		}
+		
+	} // end of class Layout
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/FisheyeDistortion.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/FisheyeDistortion.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/FisheyeDistortion.as	(revision 15)
@@ -0,0 +1,98 @@
+package gssim.gssimstudio.editor.flare.vis.operator.distortion
+{
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Computes a graphical fisheye distortion of a graph view. This distortion 
+	 * allocates more space to items near the layout anchor and less space to 
+	 * items further away, magnifying space near the anchor and demagnifying 
+	 * distant space in a continuous fashion.
+	 * 
+	 * <p>
+	 * For more details on this form of transformation, see Manojit Sarkar and 
+	 * Marc H. Brown, "Graphical Fisheye Views of Graphs", in Proceedings of 
+	 * CHI'92, Human Factors in Computing Systems, p. 83-91, 1992. Available
+	 * online at <a href="http://citeseer.ist.psu.edu/sarkar92graphical.html">
+	 * http://citeseer.ist.psu.edu/sarkar92graphical.html</a>. 
+	 * </p>
+	 */
+	public class FisheyeDistortion extends Distortion
+	{
+		private var _dx:Number; // x distortion factor
+		private var _dy:Number; // y distortion factor
+    	private var _ds:Number; // size distortion factor
+		
+		// --------------------------------------------------------------------
+		
+		/**
+	     * Create a new FisheyeDistortion with the given distortion factors
+	     * along the x and y directions.
+	     * @param dx the distortion factor along the x axis (0 for none)
+	     * @param dy the distortion factor along the y axis (0 for none)
+	     * @param ds the distortion factor to use for sizes (0 for none)
+	     */
+		public function FisheyeDistortion(dx:Number=4, dy:Number=4, ds:Number=3) {
+			_dx = dx;
+			_dy = dy;
+			_ds = ds;
+			super(_dx>0, _dy>0, _ds>0);
+		}
+		
+		/** @inheritDoc */
+		protected override function xDistort(x:Number):Number
+		{
+			return fisheye(x, layoutAnchor.x, _dx, _b.left, _b.right);
+		}
+		
+		/** @inheritDoc */
+		protected override function yDistort(y:Number):Number
+		{
+			return fisheye(y, layoutAnchor.y, _dy, _b.top, _b.bottom);
+		}
+		
+		/** @inheritDoc */
+		protected override function sizeDistort(bb:Rectangle, x:Number, y:Number):Number
+		{
+			if (!distortX && !distortY) return 1;
+			var fx:Number=1, fy:Number=1;
+			var a:Number, min:Number, max:Number, v:Number;
+			
+	        if (distortX) {
+	            a = layoutAnchor.x;
+	            min = bb.left;
+	            max = bb.right;
+	            v = Math.abs(min-a) > Math.abs(max-a) ? min : max;
+	            if (v < _b.left || v > _b.right) v = (v==min ? max : min);
+	            fx = fisheye(v, a, _dx, _b.left, _b.right);
+	            fx = Math.abs(x-fx) / (max - min);
+	        }
+	
+	        if (distortY) {
+	        	a = layoutAnchor.y;
+	        	min = bb.top;
+	        	max = bb.bottom;
+	        	v = Math.abs(min-a) > Math.abs(max-a) ? min : max;
+	        	if (v < _b.top || v > _b.bottom) v = (v==min ? max : min);
+	            fy = fisheye(v, a, _dy, _b.top, _b.bottom);
+	            fy = Math.abs(y-fy) / (max - min);
+	        }
+	        
+	        var sf:Number = (!distortY ? fx : (!distortX ? fy : Math.min(fx,fy)));
+	        return (!isFinite(sf) || isNaN(sf)) ? 1 : _ds * sf;
+		}
+		
+		private function fisheye(x:Number, a:Number, d:Number, 
+			min:Number, max:Number) : Number
+		{
+	        if (d == 0) return x;
+	        
+	        var left:Boolean = x<a;
+	        var v:Number, m:Number = (left ? a-min : max-a);
+	        if ( m == 0 ) m = max-min;
+	        v = Math.abs(x - a) / m;
+	        v = (d+1)/(d+(1/v));
+	        return (left?-1:1)*m*v + a;
+	    }
+		
+	} // end of class FisheyeDistortion
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/BifocalDistortion.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/BifocalDistortion.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/BifocalDistortion.as	(revision 15)
@@ -0,0 +1,124 @@
+package gssim.gssimstudio.editor.flare.vis.operator.distortion
+{
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Computes a bifocal distortion of space, magnifying a focus region of space
+	 * and uniformly demagnifying the rest of the space. The affect is akin to
+	 * passing a magnifying glass over the data.
+	 * 
+	 * <p>
+	 * For more details on this form of transformation, see Y. K. Leung and 
+	 * M. D. Apperley, "A Review and Taxonomy of Distortion-Oriented Presentation
+	 * Techniques", in Transactions of Computer-Human Interaction (TOCHI),
+	 * 1(2): 126-160 (1994). Available online at
+	 * <a href="portal.acm.org/citation.cfm?id=180173&dl=ACM">
+	 * portal.acm.org/citation.cfm?id=180173&dl=ACM</a>.
+	 * </p>
+	 */
+	public class BifocalDistortion extends Distortion
+	{
+		private var _rx:Number;
+		private var _mx:Number;
+		private var _ry:Number;
+		private var _my:Number;
+		
+		/**
+	     * <p>Create a new BifocalDistortion with the specified range and 
+	     * magnification along both axes.</p>
+	     * 
+	     * <p><strong>NOTE:</strong>if the range value times the magnification
+	     * value is greater than 1, the resulting distortion can exceed the
+	     * display bounds.</p>
+	     * 
+	     * @param xrange the range around the focus that should be magnified along
+	     *  the x direction. This specifies the horizontal size of the magnified 
+	     *  focus region, and should be a value between 0 and 1, 0 indicating no
+	     *  focus region and 1 indicating the whole display.
+	     * @param xmag how much magnification along the x direction should be used
+	     *  in the focal area
+	     * @param yrange the range around the focus that should be magnified along
+	     *  the y direction. This specifies the vertical size of the magnified 
+	     *  focus region, and should be a value between 0 and 1, 0 indicating no
+	     *  focus region and 1 indicating the whole display.
+	     * @param ymag how much magnification along the y direction should be used
+	     *  in the focal area
+	     */
+		public function BifocalDistortion(xRange:Number=0.1, xMagnify:Number=3,
+			yRange:Number=0.1, yMagnify:Number=3)
+		{
+			_rx = xRange;
+	        _mx = xMagnify;
+	        _ry = yRange;
+	        _my = yMagnify;
+	        distortX = !(_rx == 0 || _mx == 1.0);
+	        distortY = !(_ry == 0 || _my == 1.0);
+		}
+		
+		/** @inheritDoc */
+		protected override function xDistort(x:Number):Number
+		{
+			return bifocal(x, layoutAnchor.x, _rx, _mx, _b.left, _b.right);	
+		}
+		
+		/** @inheritDoc */
+		protected override function yDistort(y:Number):Number
+		{
+			return bifocal(y, layoutAnchor.y, _ry, _my, _b.top, _b.bottom);	
+		}
+		
+		/** @inheritDoc */
+		protected override function sizeDistort(bb:Rectangle, x:Number, y:Number):Number
+		{
+			var xmag:Boolean = false, ymag:Boolean = false;
+			var m:Number, c:Number, a:Number, min:Number, max:Number;
+        
+	        if (distortX) {
+	            c = (bb.left+bb.right)/2;
+	            a = layoutAnchor.x;
+	            min = _b.left;
+	            max = _b.right;
+	            m = c<a ? a-min : max-a;
+	            if (m == 0) m = max-min;
+	            xmag = (Math.abs(c-a) <= _rx*m )
+	        }
+	        
+	        if (distortY) {
+	            c = (bb.top+bb.bottom)/2;
+	            a = layoutAnchor.y;
+	            min = _b.top;
+	            max = _b.bottom;
+	            m = c<a ? a-min : max-a;
+	            if (m == 0) m = max-min;
+	            ymag = (Math.abs(c-a) <= _ry*m);
+	        }
+	        
+	        if (xmag && !distortY) {
+	            return _mx;
+	        } else if (ymag && !distortX) {
+	            return _my;
+	        } else if (xmag && ymag) {
+	            return Math.min(_mx, _my);
+	        } else {
+	            return Math.min((1-_rx*_mx)/(1-_rx), (1-_ry*_my)/(1-_ry));
+	        }
+		}
+		
+		private function bifocal(x:Number, a:Number, r:Number, 
+                           mag:Number, min:Number, max:Number):Number
+	    {
+	    	var m:Number, v:Number, s:Number, bx:Number;
+	        m = (x<a ? a-min : max-a);
+	        if ( m == 0 ) m = max-min;
+	        v = x - a, s = m*r;
+	        if ( Math.abs(v) <= s ) {  // in focus
+	            return v*mag + a;
+	        } else {                   // out of focus
+	            bx = r*mag;
+	            x = ((Math.abs(v)-s) / m) * ((1-bx)/(1-r));
+	            return (v<0?-1:1)*m*(x + bx) + a;
+	        }
+	    }
+		
+	} // end of class BifocalDistortion
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/Distortion.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/Distortion.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/distortion/Distortion.as	(revision 15)
@@ -0,0 +1,206 @@
+package gssim.gssimstudio.editor.flare.vis.operator.distortion
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.vis.axis.Axis;
+	import gssim.gssimstudio.editor.flare.vis.axis.CartesianAxes;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.events.VisualizationEvent;
+	import gssim.gssimstudio.editor.flare.vis.operator.layout.Layout;
+	
+	import flash.display.Sprite;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	
+	/**
+	 * Base class for distortion operators that adjust the position and size
+	 * of visual objects in a visualization.
+	 */
+	public class Distortion extends Layout
+	{
+		/** A bounding rectangle for storing the layout bounds. */
+		protected var _b:Rectangle;
+		
+		/** Flag indicating if x-coordinates should be distorted. */
+		public var distortX:Boolean;		
+		/** Flag indicating if y-coordinates should be distorted. */
+		public var distortY:Boolean;
+		/** Flag indicating if sizes should be distorted. */
+		public var distortSize:Boolean;		
+		/** Flag indicating if axes should be distorted. */
+		public var distortAxes:Boolean;		
+		/** Flag indicating if the <code>DataSprite.size</code> field should be
+		 *  distorted. If false (the default), the scaleX and scaleY properties
+		 *  are used instead. */
+		public var useSizeField:Boolean = false;		
+		/** Flag indicating if the size or scale values should be reset to 1
+		 *  upon each invocation of the distortion. This avoids the need to
+		 *  manually reset the size values on each update. The default value
+		 *  is false. */
+		public var resetSize:Boolean = false;		
+		/** Flag indicating if distortion anchor points outside the layout
+		 *  bounds should be considered by the distortion. If true, external
+		 *  anchors will be mapped to nearest point on the border of the layout
+		 *  bounds. */
+		public var anchorInBounds:Boolean = true;
+		
+		/** @inheritDoc */
+		public override function set layoutAnchor(p:Point):void {
+			if (p != null && anchorInBounds) {
+        		var b:Rectangle = layoutBounds, x:Number, y:Number;
+        		x = (p.x < b.left ? b.left : (p.x > b.right ? b.right : p.x));
+        		y = (p.y < b.top ? b.top : (p.y > b.bottom ? b.bottom : p.y));
+        		p = new Point(x, y);
+			}
+			super.layoutAnchor = p;
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new Distortion.
+		 * @param distortX Flag indicating if x-coordinates should be distorted
+		 * @param distortY Flag indicating if y-coordinates should be distorted
+		 * @param distortSize Flag indicating is sizes should be distorted
+		 */		
+		public function Distortion(distortX:Boolean=true, distortY:Boolean=true,
+			distortSize:Boolean=true, distortAxes:Boolean=true)
+		{
+			this.distortX = distortX;
+			this.distortY = distortY;
+			this.distortSize = distortSize;
+			this.distortAxes = distortAxes;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			_t = (t!=null ? t : Transitioner.DEFAULT);
+			_b = layoutBounds;
+			visualization.data.visit(distort, Data.NODES);
+			_t = null;
+			
+			if (distortAxes && visualization.xyAxes)
+				visualization.addEventListener(
+					VisualizationEvent.UPDATE, axesDistort);
+		}
+		
+		/**
+		 * Distortion method for processing a DataSprite.
+		 * @param d a DataSprite to distort
+		 */
+		protected function distort(d:DataSprite):void
+		{
+			var o:Object = _t.$(d), ss:Number;
+			if (resetSize) {
+				if (useSizeField) { o.size = 1; }
+				else { o.scaleX = 1; o.scaleY = 1; }
+			}
+			var bb:Rectangle = _t.endBounds(d, d.parent);
+			
+			if (distortX) o.x = xDistort(o.x);
+			if (distortY) o.y = yDistort(o.y);
+			if (distortSize) {
+				ss = sizeDistort(bb, o.x, o.y);
+				if (useSizeField) {
+					o.size *= ss;
+				} else {
+					o.scaleX *= ss;
+					o.scaleY *= ss;
+				}
+			}
+		}
+		
+		/**
+		 * Compute a distorted x-coordinate.
+		 * @param x the initial x-coordinate
+		 * @return the distorted s-coordinate
+		 */
+		protected function xDistort(x:Number):Number
+		{
+			// for sub-classes
+			return x;
+		}
+		
+		/**
+		 * Compute a distorted y-coordinate.
+		 * @param y the initial y-coordinate
+		 * @return the distorted y-coordinate
+		 */
+		protected function yDistort(y:Number):Number
+		{
+			// for sub-classes
+			return y;
+		}
+		
+		/**
+		 * Compute a distorted size value.
+		 * @param bb an object's bounding box
+		 * @param x the initial x-coordinate
+		 * @param y the initial y-coordinate
+		 * @return the distorted size value
+		 */
+		protected function sizeDistort(bb:Rectangle, x:Number, y:Number):Number
+		{
+			// for sub-classes
+			return 1;
+		}
+		
+		/**
+		 * Performs distortion of Cartesian axes. As axis layout is recomputed
+		 * <em>after</em> the operators have run, we must distort the axes in
+		 * a separate step. This is accomplished by adding an update listener
+		 * on the visualization that invokes the axis distortion after the
+		 * axis layout has completed. This method is registered as the
+		 * listener callback.
+		 * @param evt the visualization update event
+		 */
+		protected function axesDistort(evt:VisualizationEvent):void
+		{
+			_t = evt.transitioner;
+			_t = (_t==null ? Transitioner.DEFAULT : _t);
+			
+			var axes:CartesianAxes = visualization.xyAxes;
+			if (axes != null) {
+				distortAxis(axes.xAxis, true, false);
+				distortAxis(axes.yAxis, false, true);
+			}
+			visualization.removeEventListener(
+				VisualizationEvent.UPDATE, axesDistort);
+				
+			_t = null;
+		}
+		
+		private function distortAxis(axis:Axis, xb:Boolean, yb:Boolean):void
+		{
+			var i:int, o:Object;
+			
+			// distort the axis labels
+			var labels:Sprite = axis.labels;
+			for (i=0; i<labels.numChildren; ++i) {
+				o = _t.$(labels.getChildAt(i));
+				if (xb && distortX) {
+					o.x = xDistort(o.x);
+				}
+				if (yb && distortY) {
+					o.y = yDistort(o.y);
+				}
+			}
+			
+			// distort the axis gridlines
+			var glines:Sprite = axis.gridLines;
+			for (i=0; i<glines.numChildren; ++i) {
+				o = _t.$(glines.getChildAt(i));
+				if (xb && distortX) {
+					o.x1 = xDistort(o.x1);
+					o.x2 = xDistort(o.x2);
+				}
+				if (yb && distortY) {
+					o.y1 = yDistort(o.y1);
+					o.y2 = yDistort(o.y2);
+				}
+			}
+		}
+		
+	} // end of class Distortion
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorSwitch.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorSwitch.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorSwitch.as	(revision 15)
@@ -0,0 +1,67 @@
+package gssim.gssimstudio.editor.flare.vis.operator
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	
+	/**
+	 * An OperatorSwitch maintains a list of operators but only runs one
+	 * of these operators when invoked. A switch allows different operator
+	 * chains to be executed at different times. Operators can be added to
+	 * an OperatorSwitch using the <code>add</code> method. Once added,
+	 * operators can be retrieved and set using their index in the list, either
+	 * with array notation (<code>[]</code>) or with the
+	 * <code>getOperatorAt</code> and <code>setOperatorAt</code> methods.
+	 * 
+	 * <p>The current sub-operator to run is determined by
+	 * the <tt>index</tt> property. This index can be set manually or can
+	 * be automatically determined upon each invocation by assigning a
+	 * custom function to the <tt>indexFunction</tt> property.</p>
+	 */
+	public class OperatorSwitch extends OperatorList
+	{
+		private var _cur:int = -1;
+		
+		/** The currently active index of the switch. Only the operator at this
+		 *  index is run when the <code>operate</code> method is called. */
+		public function get index():int { return _cur; }
+		public function set index(i:int):void { _cur = i; }
+		
+		/**
+		 * A function that determines the current index value of this
+		 * OperatorSwitch. This can be used to have the operator automatically
+		 * adjust which sub-operators to run. If this property is non-null,
+		 * the function will be invoked each time this OperatorSwitch is run
+		 * and the index property will be set with the resulting value,
+		 * overriding any previous index setting.
+		 * The index function should accept zero arguments and return an
+		 * integer that is a legal index value for this switch. If the
+		 * returned value is not a legal index value (i.e., it is not an
+		 * integer or is out of bounds) then no sub-operators will be
+		 * run.
+		 */
+		public var indexFunction:Function = null;
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new OperatorSwitch.
+		 * @param ops an ordered set of operators to include in the switch.
+		 */
+		public function OperatorSwitch(...ops) {
+			for each (var op:IOperator in ops) {
+				add(op);
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			t = (t!=null ? t : Transitioner.DEFAULT);
+			if (indexFunction != null) {
+				_cur = indexFunction();
+			}
+			if (_cur >= 0 && _cur < _list.length && _list[_cur].enabled)
+				_list[_cur].operate(t);
+		}
+		
+	} // end of class OperatorSwitch
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/ColorEncoder.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/ColorEncoder.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/ColorEncoder.as	(revision 15)
@@ -0,0 +1,101 @@
+package gssim.gssimstudio.editor.flare.vis.operator.encoder
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.scale.ScaleType;
+	import gssim.gssimstudio.editor.flare.util.palette.ColorPalette;
+	import gssim.gssimstudio.editor.flare.util.palette.Palette;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	
+	/**
+	 * Encodes a data field into color values, using a scale transform and
+	 * color palette.
+	 */
+	public class ColorEncoder extends Encoder
+	{
+		private var _palette:ColorPalette;
+		private var _setPalette:Boolean = true;
+		private var _ordinal:Boolean = false;
+		
+		/** @inheritDoc */
+		public override function get palette():Palette { return _palette; }
+		public override function set palette(p:Palette):void {
+			_palette = p as ColorPalette;
+			_setPalette = (_palette == null);
+		}
+		/** The palette as a ColorPalette instance. */
+		public function get colors():ColorPalette { return _palette; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new ColorEncoder.
+		 * @param source the source property
+		 * @param group the data group to encode ("nodes" by default)
+		 * @param target the target property ("lineColor" by default)
+		 * @param scaleType the type of scale to use. If null, the scale type
+		 *  will be determined by the underlying <code>ScaleBinding</code>
+		 *  instance, based on the type of data.
+		 * @param palette the color palette to use. If null, a default color
+		 *  palette will be determined based on the scale type.
+		 */
+		public function ColorEncoder(source:String=null,
+			group:String=Data.NODES, target:String="lineColor",
+			scaleType:String=null, palette:ColorPalette=null)
+		{
+			super(source, target, group);
+			_binding.scaleType = scaleType;
+			this.palette = palette;
+		}
+		
+		/** @inheritDoc */
+		public override function setup():void
+		{
+			if (visualization==null) return;
+			super.setup();
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			_binding.updateBinding();
+			_ordinal = ScaleType.isOrdinal(_binding.scaleType);			
+			
+			// create a default color palette if none explicitly set
+			if (_setPalette) _palette = getDefaultPalette();
+			super.operate(t); // run encoder
+		}
+		
+		/** @inheritDoc */
+		protected override function encode(val:Object):*
+		{
+			if (_ordinal) {
+				return _palette.getColorByIndex(_binding.index(val));
+			} else {
+				return _palette.getColor(_binding.interpolate(val));
+			}
+		}
+		
+		/**
+		 * Returns a default color palette based on the input scale.
+		 * @param scale the scale of values to map to colors
+		 * @return a default color palette for the input scale
+		 */
+		protected function getDefaultPalette():ColorPalette
+		{
+			/// TODO: more intelligent color palette selection?
+			if (ScaleType.isOrdinal(_binding.scaleType))
+			{
+				return ColorPalette.category(_binding.length);
+			}
+			else if (ScaleType.isQuantitative(_binding.scaleType))
+			{
+				var min:Number = Number(_binding.min);
+				var max:Number = Number(_binding.max);
+				if (min < 0 && max > 0)
+					return ColorPalette.diverging();
+			}
+			return ColorPalette.ramp();
+		}
+		
+	} // end of class ColorEncoder
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/Encoder.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/Encoder.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/Encoder.as	(revision 15)
@@ -0,0 +1,119 @@
+package gssim.gssimstudio.editor.flare.vis.operator.encoder
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Filter;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.palette.Palette;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.ScaleBinding;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+
+	/**
+	 * Base class for Operators that perform encoding of visual variables such
+	 * as color, shape, and size. All Encoders share a similar structure:
+	 * A source property (e.g., a data field) is mapped to a target property
+	 * (e.g., a visual variable) using a <tt>ScaleBinding</tt> instance to map
+	 * between values and a <tt>Palette</tt> instance to map scaled output
+	 * into visual variables such as color, shape, and size.
+	 */
+	public class Encoder extends Operator
+	{
+		/** Boolean function indicating which items to process. */
+		protected var _filter:Function;
+		/** The target property. */
+		protected var _target:String;
+		/** A transitioner for collecting value updates. */
+		protected var _t:Transitioner;
+		/** A scale binding to the source data. */
+		protected var _binding:ScaleBinding;
+
+		/** A scale binding to the source data. */
+		public function get scale():ScaleBinding { return _binding; }
+		public function set scale(b:ScaleBinding):void {
+			if (_binding) {
+				if (!b.property) b.property = _binding.property;
+				if (!b.group) b.group = _binding.group;
+				if (!b.data) b.data = _binding.data;
+			}
+			_binding = b;
+		}
+
+		/** Boolean function indicating which items to process. Only items
+		 *  for which this function return true will be considered by the
+		 *  labeler. If the function is null, all items will be considered.
+		 *  @see flare.util.Filter */
+		public function get filter():Function { return _filter; }
+		public function set filter(f:*):void { _filter = Filter.$(f); }
+
+		/** The name of the data group for which to compute the encoding. */
+		public function get group():String { return _binding.group; }
+		public function set group(g:String):void { _binding.group = g; }
+		
+		/** The source property. */
+		public function get source():String { return _binding.property; }
+		public function set source(f:String):void { _binding.property = f; }
+		
+		/** The target property. */
+		public function get target():String { return _target; }
+		public function set target(f:String):void { _target = f; }
+		
+		/** The palette used to map scale values to visual values. */
+		public function get palette():Palette { return null; }
+		public function set palette(p:Palette):void { }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new Encoder.
+		 * @param source the source property
+		 * @param target the target property
+		 * @param group the data group to process
+		 * @param filter a filter function controlling which items are encoded
+		 */		
+		public function Encoder(source:String=null, target:String=null,
+							group:String=Data.NODES, filter:*=null)
+		{
+			_binding = new ScaleBinding();
+			_binding.property = source;
+			_binding.group = group;
+			_target = target;
+			this.filter = filter;
+		}
+		
+		/** @inheritDoc */
+		public override function setup():void
+		{
+			if (visualization==null) return;
+			_binding.data = visualization.data;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			if (visualization == null) return;
+			
+			_t = (t!=null ? t : Transitioner.DEFAULT);
+			var p:Property = Property.$(_binding.property);
+			_binding.updateBinding();
+			
+			visualization.data.visit(function(d:DataSprite):void {
+				_t.setValue(d, _target, encode(p.getValue(d)));
+			}, _binding.group, _filter);
+			
+			_t = null;
+		}
+		
+		/**
+		 * Computes an encoding for the input value.
+		 * @param val a data value to encode
+		 * @return the encoded visual value
+		 */
+		protected function encode(val:Object):*
+		{
+			// sub-classes can override this
+			return null;
+		}
+		
+	} // end of class Encoder
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/ShapeEncoder.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/ShapeEncoder.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/ShapeEncoder.as	(revision 15)
@@ -0,0 +1,51 @@
+package gssim.gssimstudio.editor.flare.vis.operator.encoder
+{
+	import gssim.gssimstudio.editor.flare.scale.ScaleType;
+	import gssim.gssimstudio.editor.flare.util.palette.Palette;
+	import gssim.gssimstudio.editor.flare.util.palette.ShapePalette;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	
+	/**
+	 * Encodes a data field into shape values, using an ordinal scale.
+	 * Shape values are integer indices that map into a shape palette, which
+	 * provides drawing routines for shapes. See the
+	 * <code>flare.palette.ShapePalette</code> and 
+	 * <code>flare.data.render.ShapeRenderer</code> classes for more.
+	 */
+	public class ShapeEncoder extends Encoder
+	{
+		private var _palette:ShapePalette;
+		
+		/** @inheritDoc */
+		public override function get palette():Palette { return _palette; }
+		public override function set palette(p:Palette):void {
+			_palette = p as ShapePalette;
+		}
+		/** The palette as a ShapePalette instance. */
+		public function get shapes():ShapePalette { return _palette; }
+		public function set shapes(p:ShapePalette):void { _palette = p; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new ShapeEncoder.
+		 * @param source the source property
+		 * @param group the data group to process
+		 * @param palette the shape palette for assigning shapes
+		 */
+		public function ShapeEncoder(field:String=null,
+			group:String=Data.NODES, palette:ShapePalette=null)
+		{
+			super(field, "shape", group);
+			_binding.scaleType = ScaleType.CATEGORIES;
+			_palette = palette ? palette : ShapePalette.defaultPalette();
+		}
+		
+		/** @inheritDoc */
+		protected override function encode(val:Object):*
+		{
+			return _palette.getShape(_binding.index(val));
+		}
+		
+	} // end of class ShapeEncoder
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/PropertyEncoder.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/PropertyEncoder.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/PropertyEncoder.as	(revision 15)
@@ -0,0 +1,98 @@
+package gssim.gssimstudio.editor.flare.vis.operator.encoder
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Filter;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataList;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+
+	/**
+	 * Encodes property values for a collection of visual items.
+	 * A property encoder simply sets a group of properties to static
+	 * values for all data sprites. An input object determines which
+	 * properties to set and what their values are.
+	 * 
+	 * <p>For example, a <code>PropertyEncoder</code> created with this code:
+	 * <code>new PropertyEncoder({size:1, lineColor:0xff0000ff{);</code>
+	 * will set the size to 1 and the line color to blue for all
+	 * data sprites processed by the encoder.</p>
+	 * 
+	 * <p>Property values can take a number of forms, as determined by
+	 * the <code>flare.vis.data.DataList.setProperties</code> method:
+	 * <ul>
+	 *  <li>If a value is a <code>Function</code>, it will be evaluated
+	 *      for each element and the result will be used as the property
+	 *      value for that element.</li>
+	 *  <li>If a value is an <code>IEvaluable</code> instance, such as
+	 *      <code>flare.util.Property</code> or
+	 *      <code>flare.query.Expression</code>, it will be evaluated for
+	 *      each element and the result will be used as the property value
+	 *      for that element.</li>
+	 *  <li>In all other cases, a property value will be treated as a
+	 *      literal and assigned for all elements.</li>
+	 * </ul></p>
+	 */
+	public class PropertyEncoder extends Operator
+	{
+		/** The name of the data group for which to compute the encoding. */
+		protected var _group:String;
+		/** Boolean function indicating which items to process. */
+		protected var _filter:Function;
+		/** Flag indicating if property values should be set immediately. */
+		protected var _ignoreTrans:Boolean;
+		/** The properties to set on each invocation. */
+		protected var _values:Object;
+		/** A transitioner for collecting value updates. */
+		protected var _t:Transitioner;
+		
+		/** The name of the data group for which to compute the encoding. */
+		public function get group():String { return _group; }
+		public function set group(g:String):void { _group = g; }
+		
+		/** Boolean function indicating which items to process. Only items
+		 *  for which this function return true will be considered by the
+		 *  labeler. If the function is null, all items will be considered.
+		 *  @see flare.util.Filter */
+		public function get filter():Function { return _filter; }
+		public function set filter(f:*):void { _filter = Filter.$(f); }
+		
+		public function get ignoreTransitioner():Boolean { return _ignoreTrans; }
+		public function set ignoreTransitioner(b:Boolean):void { _ignoreTrans = b; }
+		
+		/** The properties to set on each invocation. */
+		public function get values():Object { return _values; }
+		public function set values(o:Object):void { _values = o; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new PropertyEncoder
+		 * @param values The properties to set on each invocation. The input
+		 *  should be an object with a set of name/value pairs.
+		 * @param group the data group to process
+		 * @param filter a Boolean-valued function that takes a DataSprite as
+		 *  input and returns true if the sprite should be processed
+		 * @param ignoreTransitioner Flag indicating if values should be set
+		 *  immediately rather than being processed by any transitioners
+		 */		
+		public function PropertyEncoder(values:Object=null,
+			group:String=Data.NODES, filter:*=null,
+			ignoreTransitioner:Boolean=false)
+		{
+			_values = values==null ? {} : values;
+			_group = group;
+			this.filter = filter;
+			_ignoreTrans = ignoreTransitioner;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			t = (t==null || _ignoreTrans ? Transitioner.DEFAULT : t);
+			if (_values == null) return;
+			var list:DataList = visualization.data.group(_group);
+			list.setProperties(_values, t, _filter);
+		}
+		
+	} // end of class PropertyEncoder
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/SizeEncoder.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/SizeEncoder.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/encoder/SizeEncoder.as	(revision 15)
@@ -0,0 +1,57 @@
+package gssim.gssimstudio.editor.flare.vis.operator.encoder
+{
+	import gssim.gssimstudio.editor.flare.scale.ScaleType;
+	import gssim.gssimstudio.editor.flare.util.palette.Palette;
+	import gssim.gssimstudio.editor.flare.util.palette.SizePalette;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	
+	/**
+	 * Encodes a data field into size values, using a scale transform and a
+	 * size palette to determines an item's scale. The target property of a
+	 * SizeEncoder is assumed to be the <code>DataSprite.size</code> property.
+	 */
+	public class SizeEncoder extends Encoder
+	{
+		private var _palette:SizePalette;
+		
+		/** @inheritDoc */
+		public override function get palette():Palette { return _palette; }
+		public override function set palette(p:Palette):void {
+			_palette = p as SizePalette;
+		}
+		/** The palette as a SizePalette instance. */
+		public function get sizes():SizePalette { return _palette; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new SizeEncoder. By default, the scale type is set to
+		 * a quantile scale grouped into 5 bins. Adjust the values of the
+		 * <code>scale</code> property to change these defaults.
+		 * @param source the source property
+		 * @param group the data group to process
+		 * @param palette the size palette to use. If null, a default size
+		 *  palette will be used.
+		 */
+		public function SizeEncoder(source:String=null,
+			group:String=Data.NODES, palette:SizePalette=null)
+		{
+			super(source, "size", group);
+			_binding.scaleType = ScaleType.QUANTILE;
+			_binding.bins = 5;
+			if (palette) {
+				_palette = palette;
+			} else {
+				_palette = new SizePalette();
+				_palette.is2D = (group != Data.EDGES);
+			}
+		}
+		
+		/** @inheritDoc */
+		protected override function encode(val:Object):*
+		{
+			return _palette.getSize(_binding.interpolate(val));
+		}
+		
+	} // end of class SizeEncoder
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/StackedAreaLabeler.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/StackedAreaLabeler.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/StackedAreaLabeler.as	(revision 15)
@@ -0,0 +1,95 @@
+package gssim.gssimstudio.editor.flare.vis.operator.label
+{
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	
+	/**
+	 * Labeler for a stacked area chart. Use in conjunction with the
+	 * <code>StackedAreaLayout</code> operator. Adds labels to stacks whose
+	 * maximum height in pixels exceeds the minimum <code>threshold</code>
+	 * value.
+	 * 
+	 * <p><b>NOTE</b>: This has only been tested for use with horizontally
+	 * oriented stacks. In the future, this will be extended to work with
+	 * vertically oriented stacks as well.</p>
+	 */
+	public class StackedAreaLabeler extends Labeler
+	{
+		/** The minimum width for a stack to receive a label (default 12). */
+		public var threshold:Number = 12;
+		/** The base (minimum) size for labels. */
+		public var baseSize:int = 6;
+		/** Indicates the first column considered for label placement. This
+		 *  prevents columns on the edges of the display from being labeled,
+		 *  as the labels might then bleed outside the display. */
+		public var columnIndex:int = 2;
+		
+		/**
+		 * Creates a new StackedAreaLabeler. 
+		 * @param source the property from which to retrieve the label text.
+		 *  If this value is a string or property instance, the label text will
+		 *  be pulled directly from the named property. If this value is a
+		 *  Function or Expression instance, the value will be used to set the
+		 *  <code>textFunction<code> property and the label text will be
+		 *  determined by evaluating that function.
+		 */
+		public function StackedAreaLabeler(source:*=null,
+			group:String=Data.NODES)
+		{
+			super(source, group, null, null, LAYER);
+		}
+
+		/** @inheritDoc */
+		protected override function process(d:DataSprite):void
+		{
+			var label:TextSprite;
+				
+			// early exit if no chance of label visibility
+			if (!d.visible && !(_t.$(d).visible)) {
+				label = getLabel(d, false);
+				if (label) label.visible = false;
+				return;
+			}
+			label = getLabel(d, true, false);
+				
+			// find maximal point
+			var pts:Array = _t.$(d).points, len:uint = pts.length/2;
+			var i:uint, j:uint, i0:uint = 2*columnIndex;
+            var x:Number, y:Number, h:Number, height:Number=-1;
+            for (i=i0+1; i<len-i0; i+=2) {
+            	h = pts[i] - pts[pts.length-i];
+            	if (h > height) {
+            		height = h;
+            		x = pts[i-1];
+            		y = pts[i]-h/2;
+            		j = i;
+            	}
+            }
+            // hide and exit if beneath visibility threshold
+            if (height < threshold) {
+            	label.visible = false;
+            	return;
+            }
+            
+            // if label was hidden, reveal it
+			if (!label.visible && (pts=d.points)) {
+				var x0:Number=x, y0:Number=y, h0:Number=height;
+				if ((pts=d.points)) {
+					x0 = pts[j-1];
+					y0 = (pts[j] + pts[pts.length-j])/2;
+				}
+				label.visible = true;
+				label.x = x0;
+				label.y = y0;
+				label.size = 0;
+			}
+			// set the next position
+			var o:Object = _t.$(label);
+            o.x = x;
+            o.y = y;
+            o.size = baseSize + Math.sqrt(height);
+		}
+				
+	} // end of class StackedAreaLabeler
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/RadialLabeler.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/RadialLabeler.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/RadialLabeler.as	(revision 15)
@@ -0,0 +1,111 @@
+package gssim.gssimstudio.editor.flare.vis.operator.label
+{
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	
+	import flash.text.TextFormat;
+
+	/**
+	 * Labeler that positions labels around a circle in polar coordinates.
+	 * 
+	 * <p>If <code>rotateLabels</code> is set to <codetrue</code>, labels will
+	 * be rotated such that they align radially. That is, the will be aligned
+	 * along lines emanating out of the center of the circle. In this case, it
+	 * is recommend that each label's <code>textMode</code> property be set to
+	 * <code>TextSprite.EMBED</code> and that the appropriate fonts be
+	 * embedded in your application. Otherwise, the text labels may be
+	 * illegible due to rotation artifacts (for <code>BITMAP</code> labels) or
+	 * will disappear alltogether (for <code>DEVICE</code> labels).</p>
+	 */
+	public class RadialLabeler extends Labeler
+	{
+		/** If true, labels will be rotated to align along the radius. */
+		public var rotateLabels:Boolean = false;
+		
+		/** The number of pixels to offset labels along the radius. */
+		public var radiusOffset:Number = 0;
+		
+		/** The number of radians to offset a label's angle. */
+		public var angleOffset:Number = 0;
+		
+		/**
+		 * Creates a new RadialLabeler. 
+		 * @param source the property from which to retrieve the label text.
+		 *  If this value is a string or property instance, the label text will
+		 *  be pulled directly from the named property. If this value is a
+		 *  Function or Expression instance, the value will be used to set the
+		 *  <code>textFunction<code> property and the label text will be
+		 *  determined by evaluating that function.
+		 * @param rotate flag indicating if labels should be rotated to align
+		 *  along the radius. If true, all text sprite labels should use
+		 *  embedded fonts to keep the rotated labels legibile. If false,
+		 *  labels will instead have their horizontal and vertical anchor
+		 *  settings adjusted according to their angle.
+		 * @param format optional text formatting information for labels
+		 * @param filter a Boolean-valued filter function determining which
+		 *  items will be given labels
+		 * @param policy the label creation policy. One of LAYER (for adding a
+		 *  separate label layer) or CHILD (for adding labels as children of
+		 *  data objects)
+		 */
+		public function RadialLabeler(source:*=null, rotate:Boolean=false,
+			format:TextFormat=null, filter:*=null, policy:String=CHILD)
+		{
+			super(source, Data.NODES, format, filter, policy);
+			this.rotateLabels = rotate;
+		}
+		
+		/** @inheritDoc */
+		protected override function process(d:DataSprite):void
+		{
+			var label:TextSprite = getLabel(d, true);
+			var o:Object, r:Number, a:Number, b:Number, v:Boolean;
+			
+			if (_policy == LAYER) {
+				label.origin = d.origin;
+				o = _t.$(d);
+				if (o.shape == Shapes.WEDGE) {
+					r = o.h;
+					a = o.u + o.w/2;
+				} else {
+					r = o.radius;
+					a = o.angle;
+				}
+				b = o.alpha;
+				v = o.visible;
+				
+				o = _t.$(label);
+				o.radius = r + radiusOffset;
+				o.angle = a + angleOffset;
+				o.alpha = b;
+				o.visible = v;
+			} else {
+				a = _t.$(d).angle;
+				o = _t.$(label);
+				o.radius = radiusOffset;
+				o.angle  = a + angleOffset;
+			}
+			if (rotateLabels) rotate(d, label);
+			label.render();
+		}
+		
+		private function rotate(d:DataSprite, label:TextSprite):void
+		{
+			var a:Number = _t.$(d).angle;
+			while (a >  Math.PI) a -= 2*Math.PI;
+			while (a < -Math.PI) a += 2*Math.PI;
+			
+			var o:Object = _t.$(label);
+			if (a > -Math.PI/2 && a <= Math.PI/2) {
+				o.rotation = -(180/Math.PI) * a;
+				o.horizontalAnchor = TextSprite.LEFT;
+			} else {
+				o.rotation = -(180/Math.PI) * (a + Math.PI);
+				o.horizontalAnchor = TextSprite.RIGHT;
+			}
+		}
+		
+	} // end of class RadialLabeler
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/Labeler.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/Labeler.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/label/Labeler.as	(revision 15)
@@ -0,0 +1,275 @@
+package gssim.gssimstudio.editor.flare.vis.operator.label
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.util.Filter;
+	import gssim.gssimstudio.editor.flare.util.IEvaluable;
+	import gssim.gssimstudio.editor.flare.util.Property;
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+	
+	import flash.display.Sprite;
+	import flash.text.TextFormat;
+
+	/**
+	 * Labeler that adds labels for items in a visualization. By default, this
+	 * operator adds labels that are centered on each data sprite; this can be
+	 * changed by configuring the offset and anchor settings.
+	 * 
+	 * <p>Labelers support two different approaches for adding labels:
+	 * <code>CHILD</code> mode (the default) and <code>LAYER</code> mode.
+	 * <ul>
+	 *  <li>In <code>CHILD</code> mode, labels are added as children of
+	 *      <code>DataSprite</code> instances and so become part of the data
+	 *      sprite itself. In this mode, labels will automatically change
+	 *      position as data sprites are re-positioned.</li>
+	 *  <li>In <code>LAYER</code> mode, labels are instead added to a separate
+	 *      layer of the visualization above the
+	 *      <code>Visualization.marks</code> layer that contains the data
+	 *      sprites. A new layer will be created as needed and can be accessed
+	 *      through the <code>Visualization.labels</code> property. This mode
+	 *      is particularly useful for ensuring that no labels can be occluded
+	 *      by data marks. In <code>LAYER</code> mode, labels will not
+	 *      automatically move along with the labeled <code>DataSprite</code>
+	 *      instances if they are re-positioned. Instead, the labeler must be
+	 *      re-run to keep the layout current.</li>
+	 * </ul></p>
+	 * 
+	 * <p>To access created labels after a <code>Labeler</code> has been run,
+	 * use the <code>props.label</code> property of a <code>DataSprite</code>.
+	 * To have labels stored under a different property name, set the
+	 * <code>access</code> property of this class to the desired name.</p>
+	 */
+	public class Labeler extends Operator
+	{
+		/** Constant indicating that labels be placed in their own layer. */
+		public static const LAYER:String = "layer";
+		/** Constant indicating that labels be added as children. */
+		public static const CHILD:String = "child";
+		
+		/** @private */
+		protected var _policy:String;
+		/** @private */
+		protected var _labels:Sprite;
+		/** @private */
+		protected var _group:String;
+		/** @private */
+		protected var _filter:Function;
+		/** @private */
+		protected var _source:Property;
+		/** @private */
+		protected var _access:Property = Property.$("props.label");
+		/** @private */
+		protected var _cacheText:Boolean = true;
+		
+		/** @private */
+		protected var _t:Transitioner;
+		
+		/** The name of the property in which to store created labels.
+		 *  The default is "props.label". */
+		public function get access():String { return _access.name; }
+		public function set access(s:String):void { _access = Property.$(s); }
+		
+		/** The name of the data group to label. */
+		public function get group():String { return _group; }
+		public function set group(g:String):void { _group = g; setup(); }
+		
+		/** The source property that provides the label text. This
+		 *  property will be ignored if the <code>textFunction<code>
+		 *  property is non-null. */
+		public function get source():String { return _source.name; }
+		public function set source(s:String):void { _source = Property.$(s); }
+		
+		/** Boolean function indicating which items to process. Only items
+		 *  for which this function return true will be considered by the
+		 *  labeler. If the function is null, all items will be considered.
+		 *  @see flare.util.Filter */
+		public function get filter():Function { return _filter; }
+		public function set filter(f:*):void { _filter = Filter.$(f); }
+		
+		/** Boolean function indicating whether label text values should be
+		 *  cached or not.  If set to true then the label text is calculated
+		 *  only the first time it's needed and re-used from them on.  If set
+		 *  to false then the label is recalculated at each update. */
+		public function get cacheText():Boolean { return _cacheText; }
+		public function set cacheText(c:Boolean):void { _cacheText = c; }
+
+		/** A sprite containing the labels, if a layer policy is used. */
+		public function get labels():Sprite { return _labels; }
+		
+		/** The policy for how labels should be applied.
+		 *  One of LAYER (for adding a separate label layer) or
+		 *  CHILD (for adding labels as children of data objects). */
+		public function get labelPolicy():String { return _policy; }
+		
+		/** Optional function for determining label text. */
+		public var textFunction:Function = null;
+		
+		/** The text format to apply to labels. */
+		public var textFormat:TextFormat;
+		/** The text mode to use for the TextSprite labels.
+		 *  @see flare.display.TextSprite */
+		public var textMode:int = TextSprite.BITMAP;
+		/** The horizontal alignment for labels.
+		 *  @see flare.display.TextSprite */
+		public var horizontalAnchor:int = TextSprite.CENTER;
+		/** The vertical alignment for labels.
+		 *  @see flare.display.TextSprite */
+		public var verticalAnchor:int = TextSprite.MIDDLE;
+		/** The default <code>x</code> value for labels. */
+		public var xOffset:Number = 0;
+		/** The default <code>y</code> value for labels. */
+		public var yOffset:Number = 0;
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new Labeler. 
+		 * @param source the property from which to retrieve the label text.
+		 *  If this value is a string or property instance, the label text will
+		 *  be pulled directly from the named property. If this value is a
+		 *  Function or Expression instance, the value will be used to set the
+		 *  <code>textFunction<code> property and the label text will be
+		 *  determined by evaluating that function.
+		 * @param group the data group to process
+		 * @param format optional text formatting information for labels
+		 * @param filter a Boolean-valued filter function determining which
+		 *  items will be given labels
+		 * @param policy the label creation policy. One of LAYER (for adding a
+		 *  separate label layer) or CHILD (for adding labels as children of
+		 *  data objects)
+		 */
+		public function Labeler(source:*=null, group:String=Data.NODES,
+			format:TextFormat=null, filter:*=null, policy:String=CHILD)
+		{
+			if (source is String) {
+				_source = Property.$(source);
+			} else if (source is Property) {
+				_source = Property(source);
+			} else if (source is IEvaluable) {
+				textFunction = IEvaluable(source).eval;
+			} else if (source is Function) {
+				textFunction = source;
+			}
+			_group = group;
+			textFormat = format ? format : new TextFormat("Arial",12);
+			this.filter = filter;
+			
+			_policy = policy;
+		}
+		
+		/** @inheritDoc */
+		public override function setup():void
+		{
+			if (_policy == LAYER) {
+				_labels = visualization.labels;
+				if (_labels == null) {
+					_labels = new Sprite();
+					_labels.mouseChildren = false;
+					_labels.mouseEnabled = false;
+					visualization.labels = _labels;
+				}
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			_t = (t ? t : Transitioner.DEFAULT);
+			visualization.data.visit(process, group, filter);
+			_t = null;
+		}
+		
+		/**
+		 * Performs label creation and layout for the given data sprite.
+		 * Subclasses should override this method to perform custom labeling. 
+		 * @param d the data sprite to process
+		 */
+		protected function process(d:DataSprite):void
+		{
+			var label:TextSprite = getLabel(d, true);
+			var o:Object, x:Number, y:Number, a:Number, v:Boolean;
+			if (_policy == LAYER) {
+				o = _t.$(d);
+				if (o.shape == Shapes.BLOCK) { 	
+					x = o.u + o.w/2;
+					y = o.v + o.h/2;
+				} else {
+					x = o.x;
+					y = o.y;
+				}
+				a = o.alpha;
+				v = o.visible;
+				o = _t.$(label);
+				o.x = x + xOffset;
+				o.y = y + yOffset;
+				o.alpha = a;
+				o.visible = v;
+			} else {
+				o = _t.$(label);
+				o.x = xOffset;
+				o.y = yOffset;
+			}
+			label.render();
+		}
+		
+		/**
+		 * Computes the label text for a given sprite.
+		 * @param d the data sprite for which to produce label text
+		 * @return the label text
+		 */
+		protected function getLabelText(d:DataSprite):String
+		{
+			if (textFunction != null) {
+				return textFunction(d);
+			} else {
+				return _source.getValue(d);
+			}
+		}
+		
+		/**
+		 * Retrives and optionally creates a label TextSprite for the given
+		 *  data sprite. 
+		 * @param d the data sprite to process
+		 * @param create if true, a new label will be created as needed
+		 * @param visible indicates if new labels should be visible by default
+		 * @return the label
+		 */
+		protected function getLabel(d:DataSprite,
+			create:Boolean=false, visible:Boolean=true):TextSprite
+		{
+			var label:TextSprite = _access.getValue(d);
+			if (!label && !create) {
+				return null;
+			} else if (!label) {
+				label = new TextSprite("", null, textMode);
+				label.text = getLabelText(d);
+				label.visible = visible;
+				label.applyFormat(textFormat);
+				
+				_access.setValue(d, label);
+				if (_policy == LAYER) {
+					_labels.addChild(label);
+					label.x = d.x + xOffset;
+					label.y = d.y + yOffset;
+				} else {
+					d.addChild(label);
+					label.mouseEnabled = false;
+					label.mouseChildren = false;
+					label.x = xOffset;
+					label.y = yOffset;
+				}
+			} else if (label && !cacheText) {
+				var o:Object = _t.$(label);
+				o.text = getLabelText(d); 				
+			}
+			label.textMode = textMode;
+			label.horizontalAnchor = horizontalAnchor;
+			label.verticalAnchor = verticalAnchor;
+			return label;
+		}
+		
+	} // end of class Labeler
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/SortOperator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/SortOperator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/SortOperator.as	(revision 15)
@@ -0,0 +1,59 @@
+package gssim.gssimstudio.editor.flare.vis.operator
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	
+	/**
+	 * A SortOperator sorts a data group. This can be used to sort
+	 * elements prior to running a subsequent operation such as layout.
+	 * @see flare.util.Sort
+	 */
+	public class SortOperator extends Operator
+	{
+		/** The data group to sort. */
+		public var group:String;
+		
+		/** The sorting criteria. Sort criteria are expressed as an
+		 *  array of property names to sort on. These properties are accessed
+		 *  by sorting functions using the <code>Property</code> class.
+		 *  The default is to sort in ascending order. If the field name
+		 *  includes a "-" (negative sign) prefix, that variable will instead
+		 *  be sorted in descending order. */
+		public function get criteria():Array { return Arrays.copy(_crit); }
+		public function set criteria(crit:*):void {
+			if (crit is String) {
+				_crit = [crit];
+			} else if (crit is Array) {
+				_crit = Arrays.copy(crit as Array);
+			} else {
+				throw new ArgumentError("Invalid Sort specification type. " +
+					"Input must be either a String or Array");
+			}
+		}
+		private var _crit:Array;
+		
+		/**
+		 * Creates a new SortOperator.
+		 * @param criteria the sorting criteria. Sort criteria are expressed as
+		 *  an array of property names to sort on. These properties are
+		 *  accessed by sorting functions using the <code>Property</code>
+		 *  class. The default is to sort in ascending order. If the field name
+		 *  includes a "-" (negative sign) prefix, that variable will instead
+		 *  be sorted in descending order.
+		 * @param group the data group to sort
+		 */
+		public function SortOperator(criteria:Array, group:String=Data.NODES)
+		{
+			this.group = group;
+			this.criteria = criteria;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			visualization.data.group(group).sortBy(_crit);
+		}
+		
+	} // end of class SortOperator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/VisibilityFilter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/VisibilityFilter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/VisibilityFilter.as	(revision 15)
@@ -0,0 +1,91 @@
+package gssim.gssimstudio.editor.flare.vis.operator.filter
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Filter;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+
+	/**
+	 * Filter operator that sets item visibility based on a filtering
+	 * condition. Filtering conditions are specified using Boolean-valued
+	 * predicate functions that return true if the item meets the filtering
+	 * criteria and false if it does not. For items which meet the criteria,
+	 * this class sets the <code>visibility</code> property to true and
+	 * the <code>alpha</code> value to 1. For those items that do not meet
+	 * the criteria, this class sets the <code>visibility</code> property to
+	 * false and the <code>alpha</code> value to 0.
+	 * 
+	 * <p>Predicate functions can either be arbitrary functions that take
+	 * a single argument and return a Boolean value, or can be systematically
+	 * constructed using the <code>Expression</code> language provided by the
+	 * <code>flare.query</code> package.</p>
+	 * 
+	 * @see flare.query
+	 */
+	public class VisibilityFilter extends Operator
+	{
+		private var _filter:Function;
+		
+		/** Predicate function determining item visibility. */
+		public var predicate:Function;
+
+		/** The name of the data group for which to compute the encoding. 
+		 *  The default is <code>Data.NODES</code>. */
+		public var group:String;
+		
+		/** Boolean function indicating which items to process. This function
+		 *  <strong>does not</strong> determine which items will be visible, it
+		 *  only determines which items are visited by this operator. Only
+		 *  items for which this function return true will be considered by the
+		 *  VisibilityFilter. If the function is null, all items will be
+		 *  considered.
+		 *  @see flare.util.Filter */
+		public function get filter():Function { return _filter; }
+		public function set filter(f:*):void { _filter = Filter.$(f); }
+		
+		/** Immediate mode sets the visibility settings immediately, bypassing
+		 *  any transitioner provided. */
+		public var immediate:Boolean = false;
+		
+		/**
+		 * Creates a new VisibilityFilter.
+		 * @param predicate the predicate function for filtering items. This
+		 *  should be a Boolean-valued function that returns true for items
+		 *  that pass the filtering criteria and false for those that do not.
+		 * @param group the data group to process.
+		 * @param filter a Boolean-valued filter function that determines which
+		 *  items are considered by this visibility filter. Only tems that pass
+		 *  this filter will then have their visibility value set according
+		 *  to the <code>predicate</code> argument.
+		 */
+		public function VisibilityFilter(predicate:Function=null,
+						group:String=Data.NODES, filter:*=null)
+		{
+			this.predicate = predicate;
+			this.group = group;
+			this.filter = filter;
+		}
+
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			t = (t==null ? Transitioner.DEFAULT : t);
+			
+			if (immediate) {
+				visualization.data.visit(function(d:DataSprite):void {
+					var visible:Boolean = predicate(d);
+					d.alpha = visible ? 1 : 0;
+					d.visible = visible;
+				}, group, filter);
+			} else {
+				visualization.data.visit(function(d:DataSprite):void {
+					var visible:Boolean = predicate(d);
+					t.$(d).alpha = visible ? 1 : 0;
+					t.$(d).visible = visible;
+				}, group, filter);
+			}
+		}
+		
+	} // end of class VisibilityFilter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/FisheyeTreeFilter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/FisheyeTreeFilter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/FisheyeTreeFilter.as	(revision 15)
@@ -0,0 +1,155 @@
+package gssim.gssimstudio.editor.flare.vis.operator.filter
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.vis.data.Data;	
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.Tree;	
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+
+	/**
+	 * Filter operator that computes a fisheye degree-of-interest function over
+	 * a tree structure. Visibility and DOI (degree-of-interest) values are set
+	 * for the nodes and edges in the structure. This function includes a set
+	 * of focus nodes, and includes neighbors only in a limited window around
+	 * these foci. The size of this window is determined by this operator's
+	 * <code>distance</code> property. All ancestors of a focus up to the root
+	 * of the tree are considered foci as well. By convention, DOI values start
+	 * at zero for focus nodes, with decreasing negative numbers for each hop
+	 * away from a focus. The DOI values computed by this filter are stored in
+	 * the <code>DataSprite.props.doi</code> property.
+	 * 
+	 * <p>This form of filtering was described by George Furnas as early as 1981.
+	 * For more information about Furnas' fisheye view calculation and DOI values,
+	 * take a look at G.W. Furnas, "The FISHEYE View: A New Look at Structured 
+	 * Files," Bell Laboratories Tech. Report, Murray Hill, New Jersey, 1981. 
+	 * Available online at <a href="http://citeseer.nj.nec.com/furnas81fisheye.html">
+	 * http://citeseer.nj.nec.com/furnas81fisheye.html</a>.</p>
+	 */
+	public class FisheyeTreeFilter extends Operator
+	{
+		/** An array of focal NodeSprites. */
+		public var focusNodes:/*NodeSprite*/Array;
+		/** Graph distance within within which items wll be visible. */
+		public var distance:int;
+		
+		private var _divisor:Number;
+		private var _root:NodeSprite;
+		private var _t:Transitioner;
+		
+		/**
+		 * Creates a new FisheyeTreeFilter
+		 * @param focusNodes focusNodes an array of focal NodeSprites. Graph
+		 *  distance is measured as the minimum number of edge-hops to one of
+		 *  these nodes or their ancestors up to the root.
+		 * @param distance graph distance within which items will be visible
+		 */		
+		public function FisheyeTreeFilter(focusNodes:Array=null,distance:int=1)
+		{
+			this.focusNodes = focusNodes;
+			this.distance = distance;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			_t = (t==null ? Transitioner.DEFAULT : t);
+			var tree:Tree = visualization.tree;
+			_divisor = tree.nodes.length;
+        	_root = tree.root;
+        
+	        // mark the items
+	        visualization.data.visit(function(ds:DataSprite):void {
+	        	ds.props.doi = -Number.MAX_VALUE;
+	        });
+	        
+	        // compute the fisheye over nodes
+	        for each (var fn:NodeSprite in focusNodes) {
+	        	visitFocus(fn, null);
+	        }
+	        visitFocus(_root, null);
+	
+	        // mark unreached items
+	        visualization.data.visit(function(ds:DataSprite):void {
+	        	if (ds.props.doi == -Number.MAX_VALUE)
+	        		setVisibility(ds, false);
+	        });
+		}
+		
+		/**
+		 * Set the visibility of a data sprite.
+		 */
+		private function setVisibility(ds:DataSprite, visible:Boolean):void
+		{
+			var alpha:Number = visible ? 1 : 0;
+			var obj:Object = _t.$(ds);
+				
+			obj.alpha = alpha;
+			if (ds is NodeSprite)
+				(ds as NodeSprite).expanded = (ds.props.doi > -distance);
+			if (_t.immediate) {
+				ds.visible = visible;
+			} else {
+				obj.visible = visible;
+			}
+		}
+		
+		/**
+	     * Visit a focus node.
+	     */
+	    private function visitFocus(n:NodeSprite, c:NodeSprite):void
+	    {
+	        if (n.props.doi <= -1 ) {
+	            visit(n, c, 0, 0);
+	            if (distance > 0) visitDescendants(n, c);
+	            visitAncestors(n);
+	        }
+	    }
+	    
+	    /**
+	     * Visit a specific node and update its degree-of-interest.
+	     */
+	    private function visit(n:NodeSprite, c:NodeSprite, doi:int, ldist:int):void
+	    {
+	    	setVisibility(n, true);
+	        var localDOI:Number = -ldist / Math.min(1000.0, _divisor);
+	        n.props.doi = doi + localDOI;
+	        
+	        if (c != null) {
+	        	var e:EdgeSprite = c.parentEdge;
+	        	e.props.doi = c.props.doi;
+	        	setVisibility(e, true);
+	        }
+	    }
+	    
+	    /**
+	     * Visit tree ancestors and their other descendants.
+	     */
+	    private function visitAncestors(n:NodeSprite):void
+	    {
+	        if (n == _root) return;
+	        visitFocus(n.parentNode, n);
+	    }
+	    
+	    /**
+	     * Traverse tree descendents.
+	     */
+	    private function visitDescendants(p:NodeSprite, skip:NodeSprite):void
+	    {
+	    	var lidx:int = (skip == null ? 0 : skip.parentIndex);
+	        
+	        p.expanded = p.childDegree > 0;
+	        for (var i:int=0; i<p.childDegree; ++i) {
+	        	var c:NodeSprite = p.getChildNode(i);
+	        	if (c == skip) continue;
+	        	
+	        	var doi:int = int(p.props.doi - 1);
+	        	visit(c, c, doi, Math.abs(lidx-i));
+	        	if (doi > -distance) visitDescendants(c, null);
+	        }
+	    }
+
+		
+	} // end of class FisheyeTreeFilter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/GraphDistanceFilter.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/GraphDistanceFilter.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/filter/GraphDistanceFilter.as	(revision 15)
@@ -0,0 +1,106 @@
+package gssim.gssimstudio.editor.flare.vis.operator.filter
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.vis.data.DataSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.EdgeSprite;
+	import gssim.gssimstudio.editor.flare.vis.data.NodeSprite;
+	import gssim.gssimstudio.editor.flare.vis.operator.Operator;
+	
+	import flash.utils.Dictionary;
+
+	/**
+	 * Filter operator that sets visible all items within a specified graph
+	 * distance from a set of focus nodes.
+	 */
+	public class GraphDistanceFilter extends Operator
+	{
+		/** An array of focal NodeSprites. */
+		public var focusNodes:/*NodeSprite*/Array;
+		/** Graph distance within which which items wll be visible. */
+		public var distance:int;
+		/** Flag indicating which graph links to traverse. */
+		public var links:int;
+		
+		/**
+		 * Creates a new GraphDistanceFilter.
+		 * @param focusNodes an array of focal NodeSprites. Graph distance is
+		 *  measured as the minimum number of edge-hops to one of these nodes.
+		 * @param distance graph distance within which items will be visible
+		 * @param links flag indicating which graph links to traverse. The
+		 *  default value is <code>NodeSprite.GRAPH_LINKS</code>.
+		 */		
+		public function GraphDistanceFilter(focusNodes:Array=null,
+			distance:int=1, links:int=3/*NodeSprite.GRAPH_LINKS*/)
+		{
+			this.focusNodes = focusNodes;
+			this.distance = distance;
+			this.links = links;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			t = (t==null ? Transitioner.DEFAULT : t);
+	        
+	        // initialize breadth-first traversal
+	        var q:Array = [], depths:Dictionary = new Dictionary();
+			for each (var fn:NodeSprite in focusNodes) {				
+				depths[fn] = 0;
+				fn.visitEdges(function(e:EdgeSprite):void {
+					depths[e] = 1;
+					q.push(e);
+				}, links);
+			}
+			
+			// perform breadth-first traversal
+			var xe:EdgeSprite, xn:NodeSprite, d:int;
+			while (q.length > 0) {
+				xe = q.shift(); d = depths[xe];
+				// -- fix to bug 1924891 by goosebumps4all
+				if (depths[xe.source] == undefined) {
+					xn = xe.source;
+				} else if (depths[xe.target] == undefined) {
+					xn = xe.target;
+				} else {
+					continue;
+				}
+				// -- end fix
+				depths[xn] = d;
+				
+				if (d == distance) {
+					xn.visitEdges(function(e:EdgeSprite):void {
+						if (depths[e.target]==d && depths[e.source]==d) {
+							depths[e] = d+1;
+						}
+					}, links);
+				} else {
+					xn.visitEdges(function(e:EdgeSprite):void {
+						if (depths[e] == undefined) {
+							depths[e] = d+1;
+							q.push(e);
+						}
+					}, links);
+				}
+			}
+			
+			// now set visibility based on traversal results
+	        visualization.data.visit(function(ds:DataSprite):void {
+	        	var visible:Boolean = (depths[ds] != undefined);
+	        	var alpha:Number = visible ? 1 : 0;
+				var obj:Object = t.$(ds);
+				
+				obj.alpha = alpha;
+				if (ds is NodeSprite) {
+					var ns:NodeSprite = ds as NodeSprite;
+					ns.expanded = (visible && depths[ds] < distance);
+				}
+				if (t.immediate) {
+					ds.visible = visible;
+				} else {
+					obj.visible = visible;
+				}
+	        });
+		}
+		
+	} // end of class GraphDistanceFilter
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/IOperator.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/IOperator.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/IOperator.as	(revision 15)
@@ -0,0 +1,43 @@
+package gssim.gssimstudio.editor.flare.vis.operator
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.vis.Visualization;
+	
+	import mx.core.IMXMLObject;
+	
+	/**
+	 * Interface for operators that perform processing tasks on the contents
+	 * of a Visualization. These tasks include layout, and color, shape, and
+	 * size encoding. Custom operators can be defined by implementing this
+	 * interface;
+	 */
+	public interface IOperator extends IMXMLObject
+	{
+		/** The visualization processed by this operator. */
+		function get visualization():Visualization;
+		function set visualization(v:Visualization):void;
+		
+		/** Indicates if the operator is enabled or disabled. */
+		function get enabled():Boolean;
+		function set enabled(b:Boolean):void;
+		
+		/**
+		 * Sets parameter values for this operator.
+		 * @params an object containing parameter names and values.
+		 */
+		function set parameters(params:Object):void;
+		
+		/**
+		 * Performs an operation over the contents of a visualization.
+		 * @param t a Transitioner instance for collecting value updates.
+		 */
+		function operate(t:Transitioner=null):void;
+		
+		/**
+		 * Setup method invoked whenever this operator's visualization
+		 * property is set.
+		 */
+		function setup():void;
+		
+	} // end of interface IOperator
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorSequence.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorSequence.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/operator/OperatorSequence.as	(revision 15)
@@ -0,0 +1,131 @@
+package gssim.gssimstudio.editor.flare.vis.operator
+{
+	import gssim.gssimstudio.editor.flare.animate.FunctionSequence;
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.util.Arrays;
+
+	/**
+	 * An OperatorSequence maintains a list of operators that are run in
+	 * sequence with an animated transition in between each. This is in
+	 * contrast to an OperatorList, which runs all the operators at once
+	 * and constructs a single animated transition across all sub-operators.
+	 * Instead, an OperatorSequence runs each operator separately, providing
+	 * each with a different Transitioner. The result is a multi-stage
+	 * animation, in which each operator in the seqeunce get its own
+	 * sub-transition.
+	 * 
+	 * <p>The <code>add</code> method is not supported by this class. Instead,
+	 * use the <code>addToSequence</code> method, which includes the operator
+	 * to add along with a duration value (in seconds) specifying the length
+	 * of the animated transition for the operator.</p>
+	 * 
+	 * <p>An OperatorSequence is implemented by creating a
+	 * <code>flare.animate.FunctionSequence</code> instance and using it to
+	 * construct the staged animation. The <code>FunctionSequence</code> is
+	 * then added to the <code>Transitioner</code> passed in to the
+	 * <code>operate</code> method for this class. As a result, the
+	 * <code>operate</code> methods for each operator contained in the
+	 * seqeunce will not be invoked until the top-level 
+	 * <code>Transitioner</code> is played.</p>
+	 * 
+	 * <p>However, if the input <code>Transitioner</code> is null or in
+	 * immediate mode, all the operators in the sequence will be run
+	 * immediately, exactly like a normal <code>OperatorList</code>.</p>
+	 */
+	public class OperatorSequence extends OperatorList
+	{
+		/** @private */
+		protected var _times:/*Number*/Array = [];
+		
+		/**
+		 * Creates a new OperatorSequence.
+		 */
+		public function OperatorSequence()
+		{
+			super();
+		}
+		
+		/**
+		 * Adds an operator and its timing information to this operator
+		 * sequence. The operator will be invoked with a transitioner
+		 * configured with the given duration (in seconds).
+		 * @param op the operator to add to the sequence
+		 * @param duration the duration of the animated transition to be
+		 *  used for results of the given operator.
+		 */
+		public function push(op:IOperator, duration:Number):void
+		{
+			super.add(op);
+			_times.push(duration);
+		}
+		
+		/**
+		 * Sets the duration in seconds for the animated transition for the
+		 * operator at the given index.
+		 * @param i the index at which to set the duration
+		 * @param duration the desired duration, in seconds
+		 * @return the previous duration value
+		 */
+		public function setDurationAt(i:uint, duration:Number):Number
+		{
+			var old:Number = _times[i];
+			_times[i] = duration;
+			return old;
+		}
+		
+		/**
+		 * This method is not supported by this class and will throw an error
+		 * if invoked.
+		 * @param op an input operator (ignored)
+		 */
+		public override function add(op:IOperator):void
+		{
+			throw new Error("Operation not supported. Use push instead.");
+		}
+		
+		/** @inheritDoc */
+		public override function remove(op:IOperator):Boolean
+		{
+			var idx:int = Arrays.remove(_list, op);
+			if (idx >= 0) {
+				_times.splice(idx, 1);
+				return true;
+			} else {
+				return false;
+			}
+		}
+		
+		/** @inheritDoc */
+		public override function removeOperatorAt(i:uint):IOperator
+		{
+			var op:IOperator = super.removeOperatorAt(i);
+			if (op != null) _times.splice(i, 1);
+			return op;
+		}
+		
+		/** @inheritDoc */
+		public override function operate(t:Transitioner=null):void
+		{
+			if (t==null || t.immediate) {
+				super.operate(t);
+			} else {
+				var fs:FunctionSequence = new FunctionSequence();
+				for (var i:int=0; i<_list.length; ++i) {
+					if (_list[i].enabled)
+						fs.push(getFunction(_list[i]), _times[i]);
+				}
+				t.add(fs);
+			}
+		}
+		
+		private function getFunction(op:IOperator):Function {
+			return function(t:Transitioner):void {
+				op.operate(t);
+				if (visualization.axes) {
+					visualization.axes.update(t);
+				}
+			}
+		}
+		
+	} // end of class OperatorSequence
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/LegendRange.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/LegendRange.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/LegendRange.as	(revision 15)
@@ -0,0 +1,336 @@
+package gssim.gssimstudio.editor.flare.vis.legend
+{
+	import gssim.gssimstudio.editor.flare.display.RectSprite;
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.scale.IScaleMap;
+	import gssim.gssimstudio.editor.flare.scale.Scale;
+	import gssim.gssimstudio.editor.flare.util.Colors;
+	import gssim.gssimstudio.editor.flare.util.Orientation;
+	import gssim.gssimstudio.editor.flare.util.Stats;
+	import gssim.gssimstudio.editor.flare.util.palette.ColorPalette;
+	
+	import flash.display.GradientType;
+	import flash.display.Graphics;
+	import flash.display.Shape;
+	import flash.display.Sprite;
+	import flash.geom.Matrix;
+	import flash.geom.Rectangle;
+	import flash.text.TextFormat;
+
+	/**
+	 * A range in a continuous legend, consisting of a continuous
+	 * visual scale and value labels. Legend ranges use a
+	 * <code>ColorPalette</code> instance for creating a gradient of
+	 * color values. If the <code>stats</code> property
+	 * is set with the <code>Stats</code> object for a backing data
+	 * variable, a histogram of values will also be drawn in the legend
+	 * range. To draw only a histogram, set the <code>palette</code>
+	 * property to null.
+	 */
+	public class LegendRange extends RectSprite implements IScaleMap
+	{
+		private var _dataField:String;
+		private var _scale:Scale;
+		private var _stats:Stats;
+		private var _palette:ColorPalette;
+		private var _matrix:Matrix = new Matrix();
+		private var _margin:Number = 5;
+		
+		private var _labels:Sprite;
+		private var _fmt:TextFormat;
+		private var _labelMode:int = TextSprite.BITMAP;
+		
+		private var _range:Shape;
+		private var _rs:Number = 20;
+		private var _borderColor:uint = 0xcccccc;
+		private var _histogramColor:uint = 0x888888;
+		
+		private var _orient:String;
+		private var _vert:Boolean;
+		private var _rev:Boolean;
+		
+		/** The data field described by this legend range. */
+		public function get dataField():String { return _dataField; }
+		
+		/** Sprite containing the range's labels. */
+		public function get labels():Sprite { return _labels; }
+		
+		/** Stats object describing the data range. */
+		public function get stats():Stats { return _stats; }
+		public function set stats(s:Stats):void { _stats = s; dirty(); }
+		
+		/** Text format (font, size, style) of legend range labels. */
+		public function get labelTextFormat():TextFormat { return _fmt; }
+		public function set labelTextFormat(fmt:TextFormat):void {
+			_fmt = fmt; dirty();
+		}
+		
+		/** TextFormat (font, size, style) of legend range labels. */
+		public function get labelTextMode():int { return _labelMode; }
+		public function set labelTextMode(mode:int):void {
+			_labelMode = mode; dirty();
+		}
+		
+		/** Margin value for padding within the legend item. */
+		public function get margin():Number { return _margin; }
+		public function set margin(m:Number):void {
+			_margin = m; dirty();
+		}
+		
+		/** The size of the range, this is either the width or height of
+		 *  the range, depending on the current orientation. */
+		public function get rangeSize():Number { return _rs; }
+		public function set rangeSize(s:Number):void { _rs = s; }
+		
+		/** The color of the legend range border. */
+		public function get borderColor():uint { return _borderColor; }
+		public function set borderColor(c:uint):void {
+			if (c != _borderColor) { _borderColor = c; dirty(); }
+		}
+		
+		/** The color of bars in a generated histogram. */
+		public function get histogramColor():uint { return _histogramColor; }
+		public function set histogramColor(c:uint):void {
+			if (c == _histogramColor) return;
+			_histogramColor = c;
+			if (_stats) dirty();
+		}
+		
+		/** The desired orientation of this legend range. */
+		public function get orientation():String { return _orient; }
+		public function set orientation(o:String):void {
+			_orient = o;
+			_vert = Orientation.isVertical(o);
+			_rev = o==Orientation.RIGHT_TO_LEFT || o==Orientation.BOTTOM_TO_TOP;
+			dirty();
+		}
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new LegendRange.
+		 * @param dataField the data field described by this range
+		 * @param palette the color palette for the data field
+		 * @param scale the Scale instance mapping the data field to a visual
+		 *  variable
+		 */
+		public function LegendRange(dataField:String, scale:Scale,
+			palette:ColorPalette=null,
+			orientation:String=Orientation.LEFT_TO_RIGHT)
+		{
+			_dataField = dataField;
+			_palette = palette;
+			_scale = scale;
+			this.orientation = orientation;
+			addChild(_range = new Shape());
+			addChild(_labels = new Sprite());
+			_range.cacheAsBitmap = true;
+		}
+		
+		// --------------------------------------------------------------------
+		// Lookup
+		
+		/** @inheritDoc */
+		public function get x1():Number {
+			return _vert || !_rev ? _margin : _w-_margin;
+		}
+		/** @inheritDoc */
+		public function get x2():Number {
+			return _vert ? _margin+_rs : (_rev ? _margin : _w-_margin);
+		}
+		/** @inheritDoc */
+		public function get y1():Number {
+			return _vert && !_rev ? _h-_margin : _margin;
+		}
+		/** @inheritDoc */
+		public function get y2():Number {
+			return _vert ? (_rev ? _h-_margin : _margin) : _margin+_rs;
+		}
+		
+		private var _bounds:Rectangle = new Rectangle();
+				
+		/**
+		 * Bounds for the visual range portion of this legend range.
+		 * @return the bounds of the range display
+		 */
+		public function get bounds():Rectangle {
+			_bounds.x = x1;
+			_bounds.y = y1;
+			_bounds.width = x2 - x1;
+			_bounds.height = y2 - y1;
+			return _bounds;
+		}
+		
+		/** @inheritDoc */
+		public function value(x:Number, y:Number, stayInBounds:Boolean=true):Object
+        {
+        	var f:Number;
+        	if (_vert) {
+        		f = (y-_margin) / (_h - 2*_margin);
+        	} else {
+        	 	f = (x-_margin) / (_w - 2*_margin);
+        	}
+        	// correct bounds
+        	if (stayInBounds) {
+        		if (f < 0) f = 0;
+        		if (f > 1) f = 1;
+        	}
+        	if (_rev) f = 1-f;
+        	// lookup and return value
+        	return _scale.lookup(f);
+        }
+        
+        /** @inheritDoc */
+        public function X(val:Object):Number
+        {
+        	return x1 + (_vert ? 0 : _scale.interpolate(val) * (x2 - x1));
+        }
+        
+        /** @inheritDoc */
+        public function Y(val:Object):Number
+        {
+        	return y1 + (_vert ? _scale.interpolate(val) * (y2-y1) : y1);
+        }
+		
+		// --------------------------------------------------------------------
+		// Layout and Render
+		
+		/**
+		 * Update the labels shown by this legend range.
+		 */
+		public function updateLabels():void
+		{
+			var pts:Array = _palette==null ? [0,1] : _palette.keyframes;
+			var n:uint = pts.length;
+			
+			// filter for the needed number of labels
+			for (var i:uint=_labels.numChildren; i<n; ++i) {
+				_labels.addChild(new TextSprite());
+			}
+			for (i=_labels.numChildren; --i>=n;) {
+				_labels.removeChildAt(i);
+			}
+			// update and layout the labels
+			for (i=0; i<n; ++i) {
+				var ts:TextSprite = TextSprite(_labels.getChildAt(i));
+				var val:Object = _scale.lookup(pts[i]);
+				// set format
+				if (_fmt != null) ts.applyFormat(_fmt);
+				ts.textMode = _labelMode;
+				// set text
+				ts.text = _scale.label(val);
+				// set text label alignment
+				var j:uint = _vert==_rev ? i : n-i-1;
+				ts.horizontalAnchor = _vert || j==0 ? TextSprite.LEFT :
+					j==n-1 ? TextSprite.RIGHT : TextSprite.CENTER;
+				ts.verticalAnchor = !_vert || j==0 ? TextSprite.TOP :
+					j==n-1 ? TextSprite.BOTTOM : TextSprite.MIDDLE;
+				// set position
+				ts.x = _vert ? x2 : X(val);
+				ts.y = _vert ? Y(val) : y2;
+				var offset:Number = ts.height / 5;
+				if (_vert) {
+					ts.x += offset;
+					ts.y += j==0 ? -offset/2 : (j==n-1 ? offset : 0);
+				} else if (j==n-1) {
+					ts.x += offset/2;
+				}
+				ts.render();
+			}
+			// TODO adjust visibility based on overlap?
+		}
+		
+		/** @inheritDoc */
+		public override function render():void
+		{
+			updateLabels();
+			
+			var w:Number = _vert ? _rs : _w - 2*_margin;
+			var h:Number = _vert ? _h - 2*_margin : _rs;
+			_range.x = _margin;
+			_range.y = _margin;
+			_h = _vert ? _h : 2*margin + h + _labels.height;
+			
+			_range.graphics.clear();
+			
+			if (_palette != null)
+				drawPalette(w, h);
+			if (_stats != null)
+				drawHistogram(w, h);
+			
+			_range.graphics.lineStyle(0, _borderColor);
+			_range.graphics.drawRect(0, 0, w, h);
+		}
+		
+		/**
+		 * Draws a histogram of data values in the range dispay.
+		 * @param w the width of the range display
+		 * @param h the height of the range display
+		 */
+		protected function drawHistogram(w:Number, h:Number):void
+		{
+			var values:Array = _stats.values;
+			var ib:int = int(_vert ? h/2 : w/2);
+			var pb:int = (_vert ? h : w) / ib;
+			var d:Number = _vert ? w : h;
+			var i:int, f:Number;
+			
+			var counts:Array = new Array(ib);
+			for (i=0; i<counts.length; ++i) counts[i] = 0;
+			
+			for (i=0; i<values.length; ++i) {
+				f = _scale.interpolate(values[i]);
+				var idx:int = int(Math.round(f*(ib-1)));
+				counts[idx]++;
+			}
+			
+			var max:Number = 0;
+			for (i=0; i<counts.length; ++i) {
+				if (counts[i] > max) max = counts[i];
+			}
+			max = d / (1.1*max);
+			
+			var g:Graphics = _range.graphics;
+			g.beginFill(_histogramColor, _palette ? 0.5 : 1);
+			for (i=0; i<ib; ++i) {
+				var j:int = _vert==_rev ? i : ib-i-1;
+				if (_vert)
+					g.drawRect(w, h*i/ib, -max*counts[j], pb);
+				else
+					g.drawRect(w*i/ib, h, pb, -max*counts[j]);
+			}
+			g.endFill();
+		}
+		
+		/**
+		 * Draws a continuous color range in the range display.
+		 * @param w the width of the range display
+		 * @param h the height of the range display
+		 */
+		protected function drawPalette(w:Number, h:Number):void
+		{
+			// build gradient paint parameters
+			var N:int = _palette.keyframes.length;
+			var colors:Array = new Array(N);
+			var alphas:Array = new Array(N);
+			var ratios:Array = new Array(N);
+			for (var i:uint=0; i<N; ++i) {
+				var c:uint = _palette.getColor(_palette.keyframes[i]);
+				colors[i] = 0x00ffffff & c;
+				alphas[i] = Colors.a(c) / 255;
+				ratios[i] = int(255 * _palette.keyframes[i]);
+			}
+			var rot:Number = _vert ? (_rev ? 1 : -1) * Math.PI/2
+								   : (_rev ? Math.PI : 0);
+			_matrix.createGradientBox(w, h, rot);
+			
+			// paint the color palette
+			var g:Graphics = _range.graphics;
+			g.beginGradientFill(GradientType.LINEAR,
+				colors, alphas, ratios, _matrix);
+			g.drawRect(0, 0, w, h);
+			g.endFill();
+		}
+		
+	} // end of class LegendRange
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/LegendItem.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/LegendItem.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/LegendItem.as	(revision 15)
@@ -0,0 +1,148 @@
+package gssim.gssimstudio.editor.flare.vis.legend
+{
+	import gssim.gssimstudio.editor.flare.display.RectSprite;
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.util.Shapes;
+	
+	import flash.display.Graphics;
+	import flash.display.Shape;
+
+	/**
+	 * An item in a discrete legend consisting of a label and
+	 * an icon indicating color, shape, and/or size.
+	 */
+	public class LegendItem extends RectSprite
+	{
+		private var _value:Object;
+		
+		private var _icon:Shape;
+		private var _iconLineWidth:Number = 2;
+		private var _label:TextSprite;
+		
+		private var _iconSize:Number = 12;
+		private var _maxIconSize:Number = 12;
+		private var _margin:Number = 5;
+		
+		private var _shape:String;
+		private var _color:uint;
+		
+		private var _selected:Boolean = false;
+		
+		// -- Properties ------------------------------------------------------
+		
+		/** The data value represented by this legend item. */
+		public function get value():Object { return _value; }
+		public function set value(v:Object):void { _value = v; }
+		
+		/** Shape presenting this legend item's icon. */
+		public function get icon():Shape { return _icon; }
+		/** TextSprite presenting this legend item's label. */
+		public function get label():TextSprite { return _label; }
+		
+		/** The label text. */
+		public function get text():String { return _label.text; }
+		public function set text(t:String):void {
+			if (t != _label.text) { _label.text = t; dirty(); }
+		}
+		
+		/** Line width to use within the icon. */
+		public function get iconLineWidth():Number { return _iconLineWidth; }
+		public function set iconLineWidth(s:Number):void {
+			if (s != _iconLineWidth) { _iconLineWidth = s; dirty(); }
+		}
+		
+		/** Size parameter for icon drawing. */
+		public function get iconSize():Number { return _iconSize; }
+		public function set iconSize(s:Number):void {
+			if (s != _iconSize) { _iconSize = s; dirty(); }
+		}
+		
+		/** Maximum size parameter for icon drawing. */
+		public function get maxIconSize():Number { return _maxIconSize; }
+		public function set maxIconSize(s:Number):void {
+			if (s != _maxIconSize) { _maxIconSize = s; dirty(); }
+		}
+		
+		/** Margin value for padding within the legend item. */
+		public function get margin():Number { return _margin; }
+		public function set margin(m:Number):void {
+			if (m != _margin) { _margin = m; dirty(); }
+		}
+		
+		/** The inner width of this legend item. */
+		public function get innerWidth():Number {
+			return 2*_margin + _maxIconSize + 
+				(_label.text.length>0 ? _margin + _label.width : 0);
+		}
+		/** The inner height of this legend item. */
+		public function get innerHeight():Number {
+			return Math.max(2*_margin + _maxIconSize, _label.height);
+		}
+		
+		/** Flag indicating if this legend item has been selected. */
+		public function get selected():Boolean { return _selected; }
+		public function set selected(b:Boolean):void { _selected = b; }
+		
+		// -- Methods ---------------------------------------------------------
+		
+		/**
+		 * Creates a new LegendItem.
+		 * @param text the label text
+		 * @param color the color of the label icon
+		 * @param shape a shape drawing function for the label icon
+		 * @param iconSize a size parameter for drawing the label icon
+		 */
+		public function LegendItem(text:String=null, color:uint=0xff888888,
+								   shape:String=null, iconSize:Number=NaN)
+		{
+			addChild(_icon = new Shape());
+			addChild(_label = new TextSprite(text));
+			
+			// init background
+			super(0,0,0, 2*_margin + _iconSize, 13, 13);
+			lineColor = 0;
+			fillColor = 0;
+			
+			// init label
+			_label.horizontalAnchor = TextSprite.LEFT;
+			_label.verticalAnchor = TextSprite.MIDDLE;
+			_label.mouseEnabled = false;
+			
+			// init icon
+			_color = color;
+			_shape = shape;
+			if (!isNaN(iconSize)) _iconSize = iconSize;
+		}
+		
+		/** @inheritDoc */
+		public override function render():void
+		{			
+			// layout label
+			_label.x = 2*_margin + _maxIconSize;
+			_label.y = innerHeight / 2;
+			// TODO compute text abbrev as needed?
+			
+			// layout icon
+			_icon.x = _margin + _maxIconSize/2;
+			_icon.y = innerHeight / 2;
+			if (_label.textMode != TextSprite.EMBED) _icon.y -= 1;
+			
+			// render icon
+			var draw:Function = _shape ? Shapes.getShape(_shape) : null;
+			var g:Graphics = _icon.graphics;
+			g.clear();
+			if (draw != null) {
+				g.lineStyle(_iconLineWidth, _color, 1);
+				draw(g, _iconSize/2);
+			} else {
+				g.beginFill(_color);
+				Shapes.drawCircle(g, _iconSize/2);
+				g.endFill();
+			}
+			
+			_h = innerHeight;
+			super.render();
+		}
+		
+	} // end of class LegendItem
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/Legend.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/Legend.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/vis/legend/Legend.as	(revision 15)
@@ -0,0 +1,571 @@
+package gssim.gssimstudio.editor.flare.vis.legend
+{
+	import gssim.gssimstudio.editor.flare.animate.Transitioner;
+	import gssim.gssimstudio.editor.flare.display.RectSprite;
+	import gssim.gssimstudio.editor.flare.display.TextSprite;
+	import gssim.gssimstudio.editor.flare.scale.Scale;
+	import gssim.gssimstudio.editor.flare.scale.ScaleType;
+	import gssim.gssimstudio.editor.flare.util.Displays;
+	import gssim.gssimstudio.editor.flare.util.Orientation;
+	import gssim.gssimstudio.editor.flare.util.palette.ColorPalette;
+	import gssim.gssimstudio.editor.flare.util.palette.Palette;
+	import gssim.gssimstudio.editor.flare.util.palette.ShapePalette;
+	import gssim.gssimstudio.editor.flare.util.palette.SizePalette;
+	import gssim.gssimstudio.editor.flare.vis.data.ScaleBinding;
+	
+	import flash.display.Sprite;
+	import flash.geom.Rectangle;
+	import flash.text.TextFormat;
+	
+	/**
+	 * A legend describing the visual encoding of a data property. Legends
+	 * support both discrete legends that list individual items and
+	 * range legends the convey a continuous range of values. Discrete
+	 * legends consist of a collection of <code>LegendItem</code> instances
+	 * stored in the <code>items</code> sprite. Range legends consist of
+	 * a single <code>LegendRange</code> instance stored in the
+	 * <code>items</code> sprite.
+	 * 
+	 * <p>There are multiple ways to generate a legend. To build a legend
+	 * based on an existing visual encoding, use the static
+	 * <code>fromScale</code> constructor. This method takes a data scale
+	 * and one more or more palettes (e.g., color, shape, or size palettes)
+	 * and uses them to generate an appropriate legend. If the data scale
+	 * is a quantitative scale and only a color palette is provided, a
+	 * continuous range legend will be generated. Otherwise, a discrete
+	 * legend will be created.</p>
+	 * 
+	 * <p>Legends can also be created from a collection of independent
+	 * values using the static <code>fromValues</code> constructor. This
+	 * method takes an array of legend item descriptions and uses them to
+	 * generate a legend. For example, consider this code:</p>
+	 * 
+	 * <pre>
+	 * var legend:Legend = Legend.fromValues("Legend Title", [
+	 *   {color: 0xff0000, shape:Shapes.X, label:"Red X"},
+	 *   {color: 0x00ff00, shape:Shapes.SQUARE, label:"Green Square"},
+	 *   {color: 0x0000ff, shape:Shapes.CIRCLE, label:"Blue Circle"}
+	 * ]);
+	 * </pre>
+	 * 
+	 * <p>This example will create a legend with the described values.
+	 * See the documentation for the <code>buildFromValues</code> method
+	 * for more details.</p>
+	 */
+	public class Legend extends Sprite
+	{
+		/** @private The layout bounds for this legend instance. */
+		protected var _bounds:Rectangle = null;
+
+		/** @private Sprite defining the border of the legend. */
+		protected var _border:RectSprite;
+		/** @private Sprite containing the legend items. */
+		protected var _items:Sprite;
+		/** @private TextSprite containing the legend title.*/
+		protected var _title:TextSprite;
+		
+		/** @private Scale instance used to define the legend mapping. */
+		protected var _scale:Scale;
+		/** @private Flag for if this legend is discrete or continuous. */
+		protected var _discrete:Boolean = true;
+		
+		/** @private The default color to use for legend items. */
+		protected var _defaultColor:uint = 0xff888888;
+		/** @private The color palette used to encode values (may be null). */
+		protected var _colors:ColorPalette;
+		/** @private The shape palette used to encode values (may be null). */
+		protected var _shapes:ShapePalette;
+		/** @private The size palette used to encode values (may be null). */
+		protected var _sizes:SizePalette;
+		
+		/** @private Flag indicating the desired orientation of this legend. */
+		protected var _orient:String = null;
+		/** @private Margins within legend items. */
+		protected var _margin:Number = 4;
+		/** @private Spacing between legend items. */
+		protected var _spacing:Number = 0;
+		/** @private Base icon size */
+		protected var _baseIconSize:Number = 12;
+
+		/** @private TextFormat (font, size, style) of legend item labels. */
+		protected var _labelTextFormat:TextFormat = new TextFormat("Arial",12,0);	
+		/** @private Label text mode. */
+		protected var _labelTextMode:int = TextSprite.BITMAP;
+	
+		/** @private The calculated internal width of the legend. */
+		protected var _iw:Number;
+		/** @private The calculated internal height of the legend. */
+		protected var _ih:Number;
+
+		// -- Properties ------------------------------------------------------
+
+		/** The layout bounds for this legend instance. */
+		public function get bounds():Rectangle { return _bounds; }
+		public function set bounds(b:Rectangle):void { _bounds = b; }
+		
+		/** Sprite defining the border of the legend. */
+		public function get border():RectSprite { return _border; }
+		/** Sprite containing the legend items. */
+		public function get items():Sprite { return _items; }
+		/** TextSprite containing the legend title.*/
+		public function get title():TextSprite { return _title; }
+		
+		/** Flag indicating if this legend is discrete or continuous. */
+		public function get discrete():Boolean { return _discrete; }
+		
+		/** Scale instance used to define the legend mapping. */
+		public function get scale():Scale { return _scale; }
+		public function set scale(s:Scale):void { _scale = s; }
+		/** The legend range, if this legend is continuous. This
+		 *  value is null if the legend is discrete. */
+		public function get range():LegendRange {
+			return _discrete ? null : LegendRange(_items.getChildAt(0));
+		}
+
+		/** The default color to use for legend items. */		
+		public function get defaultColor():uint { return _defaultColor; }
+		public function set defaultColor(c:uint):void { _defaultColor = c; }
+
+		/** The color palette used to encode values (may be null). */		
+		public function get colorPalette():ColorPalette { return _colors; }
+		public function set colorPalette(cp:ColorPalette):void { _colors = cp; }
+
+		/** The shape palette used to encode values (may be null). */		
+		public function get shapePalette():ShapePalette { return _shapes; }
+		public function set shapePalette(sp:ShapePalette):void { _shapes = sp; }
+
+		/** The size palette used to encode values (may be null). */		
+		public function get sizePalette():SizePalette { return _sizes; }
+		public function set sizePalette(sp:SizePalette):void { _sizes = sp; }
+		
+		/** The desired orientation of this legend. */
+		public function get orientation():String { return _orient; }
+		public function set orientation(o:String):void { _orient = o; }
+
+		/** Margins within legend items. */		
+		public function get margin():Number { return _margin; }
+		public function set margin(m:Number):void { _margin = m; }
+
+		/** Spacing between legend items. */		
+		public function get spacing():Number { return _spacing; }
+		public function set spacing(s:Number):void { _spacing = s; }
+
+		/** Base icon size, corresponding to a size factor of 1. */
+		public function get baseIconSize():Number { return _baseIconSize; }
+		public function set baseIconSize(s:Number):void {
+			if (_baseIconSize != s && _discrete) {
+				for (var i:uint=0; i<_items.numChildren; ++i) {
+					var li:LegendItem = LegendItem(_items.getChildAt(i));
+					li.iconSize *= (s / _baseIconSize);
+					li.maxIconSize *= (s / _baseIconSize);
+				}
+			}
+			_baseIconSize = s;
+		}
+
+		/** TextFormat (font, size, style) of legend item labels. */		
+		public function get labelTextFormat():TextFormat { return _labelTextFormat; }
+		public function set labelTextFormat(f:TextFormat):void {
+			_labelTextFormat = f; updateItems();
+		}
+		
+		/** Label text mode. */
+		public function get labelTextMode():int { return _labelTextMode; }
+		public function set labelTextMode(mode:int):void {
+			_labelTextMode = mode; updateItems();
+		}
+		
+		// -- Initialization --------------------------------------------------
+		
+		/**
+		 * Creates a new Legend for the given data field.
+		 * @param dataField the data field to describe with the legend
+		 * @param vis the visualization corresponding to this legend
+		 * @param scale the scale value used to map the data field to visual
+		 *  variables
+		 */
+		public function Legend(title:String, scale:Scale=null,
+			colors:ColorPalette=null, shapes:ShapePalette=null,
+			sizes:SizePalette=null)
+		{
+			this.scale = scale;
+			addChild(_border = new RectSprite(0,0,0,0,13,13));
+			addChild(_title = new TextSprite());
+			addChild(_items = new Sprite());
+			_border.lineColor = 0;
+			_border.fillColor = 0;
+			
+			_colors = colors;
+			_shapes = shapes;
+			_sizes = sizes;
+			
+			_title.textField.defaultTextFormat = 
+				new TextFormat("Arial",12,null,true);
+			if (title != null)
+				_title.text = title;
+			else
+				_title.visible = false;
+			
+			if (scale != null) {
+				buildFromScale();
+				update();
+			}
+		}
+		
+		/**
+		 * Update the legend, recomputing layout of items.
+		 * @param t a transitioner for value updates
+		 * @return the input transitioner
+		 */
+		public function update(t:Transitioner=null):Transitioner
+		{
+			if (_scale is ScaleBinding && ScaleBinding(_scale).updateBinding())
+				buildFromScale();
+			updateItems();
+			layout(t);
+			return t;
+		}
+		
+		/**
+		 * Builds the contents of this legend from the current scale values.
+		 * This method will remove all items from the legend and rebuild the
+		 * legend using the current scale and palette settings.
+		 */
+		public function buildFromScale():void
+		{
+			// first, remove all items
+			while (_items.numChildren > 0) {
+				_items.removeChildAt(_items.numChildren-1);
+			}
+					
+			// determine legend type
+			var type:String = _scale.scaleType;
+			if (ScaleType.isQuantitative(type) && !_sizes && !_shapes) {
+				// build continuous legend
+				_discrete = false;
+				if (!_orient) _orient = Orientation.LEFT_TO_RIGHT;
+				_items.addChild(new LegendRange(_title.text,
+					_scale,	_colors, _orient));
+			} else {
+				// build discrete legend
+				_discrete = true;
+				if (!_orient) _orient = Orientation.TOP_TO_BOTTOM;
+				
+				var numVals:int = ScaleType.isQuantitative(type) ? 5 : -1;
+				var maxSize:Number = Number.MIN_VALUE;
+				var vals:Array = _scale.values(numVals);
+				for (var i:uint=0; i<vals.length; ++i) {
+					// determine legend item properties
+					var f:Number = _scale.interpolate(vals[i]);
+					var color:uint = _defaultColor;
+					if (_colors && ScaleType.isOrdinal(type)) {
+						color = _colors.getColorByIndex(i);
+					} else if (_colors) {
+						color = _colors.getColor(f);
+					}
+					var shape:String = _shapes ? _shapes.getShape(i) : null;
+					var size:Number = _baseIconSize*(_sizes?_sizes.getSize(f):1);
+					if (size > maxSize) maxSize = size;
+					
+					var item:LegendItem = new LegendItem(
+						_scale.label(vals[i]), color, shape, size);
+					item.value = vals[i];
+					_items.addChild(item);
+				}
+				for (i=0; i<_items.numChildren; ++i)
+					LegendItem(_items.getChildAt(i)).maxIconSize = maxSize;
+			}
+		}
+		
+		/**
+		 * Populates the contents of this legend from a list of value objects.
+		 * This method will create a legend with discrete entries determined by
+		 * the contents of the input <code>values</code> array. This should be
+		 * an array of objects containing the following properties:
+		 * <ul>
+		 *  <li><code>value</code>: The data value the legend item represents.
+		 *    This value is not required.</li>
+		 *  <li><code>label</code>: The text label to place in the legend item.
+		 *    If this value is not provided, the method will attempt to
+		 *    generate a label string from the <code>value</code> property.</li>
+		 *  <li><code>color</code>: The color for the legend item. If missing,
+		 *    this legend's default color will be used.</li>
+		 *  <li><code>shape</code>: The shape for the legend item. If missing,
+		 *    a default circle shape will be used.</li>
+		 *  <li><code>size</code>: The size for the legend item. If missing,
+		 *    a size value of 1 will be used.</li>
+		 * </ul>
+		 * When this method is called, any previous values in the legend will
+		 * be removed.
+		 * @param values an array of value to include in the legend.
+		 */
+		public function buildFromValues(values:Array):void
+		{
+			// first, remove all items
+			while (_items.numChildren > 0) {
+				_items.removeChildAt(_items.numChildren-1);
+			}
+			_discrete = true;
+			if (!_orient) _orient = Orientation.TOP_TO_BOTTOM;
+			
+			var maxSize:Number = Number.MIN_VALUE;
+			for each (var v:Object in values) {
+				var value:Object = v.value != undefined ? v.value : null;
+				var label:String = v.label ? v.label.toString() : value ? value.toString() : "???";
+				var color:uint = v.color != undefined ? uint(v.color) : _defaultColor;
+				var shape:String = v.shape ? v.shape as String : null;
+				var size:Number = _baseIconSize*(v.size is Number ? v.size : 1);
+				if (size > maxSize) maxSize = size;
+				
+				var item:LegendItem = new LegendItem(label, color, shape, size);
+				item.value = value;
+				item.margin = margin;
+				_items.addChild(item);
+			}
+			for (var i:uint=0; i<_items.numChildren; ++i)
+				LegendItem(_items.getChildAt(i)).maxIconSize = maxSize;
+		}
+		
+		// -- Layout ----------------------------------------------------------
+		
+		/**
+		 * Performs layout, setting the position for all items in the legend.
+		 * @param t a transitioner for value updates
+		 */
+		public function layout(t:Transitioner=null):void
+		{
+			t = (t ? t : Transitioner.DEFAULT);
+			
+			var vert:Boolean = Orientation.isVertical(_orient);
+			var o:Object;
+			var b:Rectangle = bounds;
+			var x:Number = b ? b.left : 0;
+			var y:Number = b ? b.top : 0;
+			var w:Number, h:Number, th:Number = 0;
+			
+			// layout the title
+			o = t.$(_title);
+			if (_title.text != null && _title.text.length > 0) {
+				o.x = x + _margin;
+				o.alpha = 1;
+				_title.visible = true;
+				y += (th = _title.height + (vert?_spacing:0));
+			} else {
+				o.alpha = 0;
+				o.visible = false;
+			}
+			
+			// layout item container
+			o = t.$(_items);
+			o.x = x;
+			o.y = y;
+			
+			// layout items
+			if (_discrete) {
+				layoutDiscrete(t);
+			} else {
+				layoutContinuous(t);
+			}
+			
+			w = b ? (vert ? b.width : Math.min(_iw, b.width)) : _iw;
+			h = b ? (vert ? Math.min(_ih, b.height) : _ih) : _ih;
+			
+			// size the border
+			o = t.$(_border);
+			o.x = x;
+			o.y = b ? b.top : 0;
+			o.w = w;
+			o.h = h + th;
+			if (t.immediate) _border.render();
+			
+			// create clipping panel
+			t.$(items).scrollRect = new Rectangle(0, 0, 1+w, 1+h);
+		}
+		
+		/**
+		 * @private
+		 * Layout helper for positioning discrete legend items.
+		 * @param t a transitioner for value updates
+		 */
+		protected function layoutDiscrete(t:Transitioner):void
+		{
+			var vert:Boolean = Orientation.isVertical(_orient);
+			var rev:Boolean = _orient == Orientation.RIGHT_TO_LEFT ||
+							  _orient == Orientation.BOTTOM_TO_TOP;
+			var x:Number = 0, y:Number = 0, i:uint, j:uint;
+			var item:LegendItem, o:Object;
+			var bw:Number = vert && bounds ? bounds.width : NaN;
+			
+			// if needed, compute shared width for legend items
+			if (vert && isNaN(bw)) {
+				bw = Number.MIN_VALUE;
+				for (i=0; i<_items.numChildren; ++i) {
+					item = _items.getChildAt(i) as LegendItem;
+					bw = Math.max(bw, item.innerWidth);
+				}
+			}
+			
+			_iw = _ih = 0;
+			for (i=0; i<_items.numChildren; ++i) {
+				j = rev ? _items.numChildren-i-1 : i;
+				// layout the item
+				item = _items.getChildAt(j) as LegendItem;
+				o = t.$(item);
+				o.x = x;
+				o.y = y;
+				o.w = isNaN(bw) ? item.innerWidth : bw;
+				
+				// increment spacing
+				if (vert) {
+					y += item.innerHeight + _spacing;
+					_iw = Math.max(_iw, item.innerWidth);
+				}
+				else {
+					x += item.innerWidth + _spacing;
+					_ih = Math.max(_ih, item.innerHeight);
+				}
+			}
+			_iw = vert ? _iw : x-_spacing;
+			_ih = vert ? y-_spacing : _ih;
+		}
+		
+		/**
+		 * @private
+		 * Layout helper for positioning a continous legend range.
+		 * @param trans a transitioner for value updates
+		 */
+		protected function layoutContinuous(t:Transitioner):void
+		{
+			var lr:LegendRange = _items.getChildAt(0) as LegendRange;
+			lr.orientation = _orient;
+			if (Orientation.isHorizontal(_orient)) {
+				_iw = lr.w = bounds ? bounds.width : 200;
+				lr.updateLabels();
+				_ih = lr.height + lr.margin;
+			} else {
+				_ih = lr.h = bounds ? bounds.height : 200;
+				lr.updateLabels();
+				_iw = lr.width;
+			}
+		}
+		
+		// -- Legend Items ----------------------------------------------------
+		
+		/** @private */
+		protected function updateItems() : void
+		{
+			if (_items.numChildren == 0) {
+				return;
+			} else if (_discrete) {
+				for (var i:uint = 0; i<_items.numChildren; ++i)
+					updateItem(_items.getChildAt(i) as LegendItem);
+			} else {
+				updateRange(_items.getChildAt(0) as LegendRange);
+			}
+		}
+		
+		/** @private */
+		protected function updateItem(item:LegendItem):void
+		{
+			item.label.textMode = _labelTextMode;
+			item.label.applyFormat(_labelTextFormat);
+			item.margin = _margin;
+		}
+		
+		/** @private */
+		protected function updateRange(range:LegendRange):void
+		{
+			range.labelTextMode = _labelTextMode;
+			range.labelTextFormat = _labelTextFormat;
+			range.margin = _margin;
+		}
+		
+		/**
+		 * Sets property values on all legend items. The values
+		 * within the <code>vals</code> argument can take a number of forms:
+		 * <ul>
+		 *  <li>If a value is a <code>Function</code>, it will be evaluated
+		 *      for each element and the result will be used as the property
+		 *      value for that element.</li>
+		 *  <li>If a value is an <code>IEvaluable</code> instance, such as
+		 *      <code>flare.util.Property</code> or
+		 *      <code>flare.query.Expression</code>, it will be evaluated for
+		 *      each element and the result will be used as the property value
+		 *      for that element.</li>
+		 *  <li>In all other cases, a property value will be treated as a
+		 *      literal and assigned for all elements.</li>
+		 * </ul>
+		 * @param vals an object containing the properties and values to set.
+		 * @param t a transitioner or time span for updating object values. If
+		 *  the input is a transitioner, it will be used to store the updated
+		 *  values. If the input is a number, a new Transitioner with duration
+		 *  set to the input value will be used. The input is null by default,
+		 *  in which case object values are updated immediately.
+		 * @return the transitioner used to update the values
+		 */
+		public function setItemProperties(vals:Object, t:*=null):Transitioner
+		{
+			var trans:Transitioner = Transitioner.instance(t);
+			Displays.setChildrenProperties(items, vals, trans);
+			return trans;
+		}
+		
+		// -- Static Constructors ---------------------------------------------
+		
+		/**
+		 * Generates a legend from a given scale and one or more palettes.  If
+		 * multiple palettes of the same type are provided, only the first of
+		 * each type will be used for the legend, the others will be ignored.
+		 * @param title the title text for the legend
+		 * @param scale the scale instance determining the legend values
+		 * @param palette a color, shape, or size palette for legend items
+		 * @param args one or more additional palettes
+		 * @return the generated Legend, or null if a legend could not be built
+		 */
+		public static function fromScale(title:String, scale:Scale,
+			palette:Palette, ...args):Legend
+		{
+			if (scale == null || palette == null)
+				return null;
+				
+			var colors:ColorPalette;
+			var shapes:ShapePalette;
+			var sizes:SizePalette;
+			
+			// construct palette collection
+			var palettes:Array = args as Array;
+			palettes.unshift(palette);
+			for each (var p:Palette in palettes) {
+				if (p is ColorPalette && !colors)
+					colors = ColorPalette(p);
+				else if (p is ShapePalette && !shapes)
+					shapes = ShapePalette(p);
+				else if (p is SizePalette && !sizes)
+					sizes = SizePalette(p);
+			}
+			if (!colors && !shapes && !sizes)
+				return null; // no palette to use
+			
+			return new Legend(title, scale, colors, shapes, sizes);
+		}
+		
+		/**
+		 * Generates a legend from an array of legend item values. This method
+		 * simply instantiates a new <code>Legend</code> instance with the
+		 * given title and then invokes the <code>buildFromValues</code> method
+		 * with the given value array.
+  		 * @param title the legend title text, or null for no title.
+  		 * @param values an array of values for the legend items. See the
+		 *  documentation for the <code>buildFromValues</code> method for more.
+		 * @return the generated legend
+		 */
+		public static function fromValues(title:String, values:Array):Legend
+		{
+			var legend:Legend = new Legend(title);
+			legend.buildFromValues(values);
+			legend.update();
+			return legend;
+		}
+		
+	} // end of class Legend
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/NBodyForce.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/NBodyForce.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/NBodyForce.as	(revision 15)
@@ -0,0 +1,315 @@
+package gssim.gssimstudio.editor.flare.physics
+{
+	/**
+	 * Force simulating an N-Body force of charged particles with pairwise
+	 * interaction, such as gravity or electrical charge. This class uses a
+	 * quad-tree structure to aggregate charge values and optimize computation.
+	 * The force function is a standard inverse-square law (though in this case
+	 * approximated due to optimization): <code>F = G * m1 * m2 / d^2</code>,
+	 * where G is a constant (e.g., gravitational constant), m1 and m2 are the
+	 * masses (charge) of the particles, and d is the distance between them.
+	 * 
+	 * <p>The algorithm used is that of J. Barnes and P. Hut, in their research
+	 * paper <i>A Hierarchical  O(n log n) force calculation algorithm</i>, Nature, 
+	 * v.324, December 1986. For more details on the algorithm, see one of
+	 * the following links:
+	 * <ul>
+	 *   <li><a href="http://www.cs.berkeley.edu/~demmel/cs267/lecture26/lecture26.html">James Demmel's UC Berkeley lecture notes</a>
+	 *   <li><a href="http://www.physics.gmu.edu/~large/lr_forces/desc/bh/bhdesc.html">Description of the Barnes-Hut algorithm</a>
+	 *   <li><a href="http://www.ifa.hawaii.edu/~barnes/treecode/treeguide.html">Joshua Barnes' implementation</a>
+	 * </ul></p>
+	 */
+	public class NBodyForce implements IForce
+	{
+		private var _g:Number;     // gravitational constant
+		private var _t:Number;     // barnes-hut theta
+		private var _max:Number;   // max effective distance
+		private var _min:Number;   // min effective distance
+		private var _eps:Number;   // epsilon for determining 'same' location
+		
+		private var _x1:Number, _y1:Number, _x2:Number, _y2:Number;
+		private var _root:QuadTreeNode;
+		
+		/** The gravitational constant to use. 
+		 *  Negative values produce a repulsive force. */
+		public function get gravitation():Number { return _g; }
+		public function set gravitation(g:Number):void { _g = g; }
+		
+		/** The maximum distance over which forces are exerted. 
+		 *  Any greater distances will be ignored. */
+		public function get maxDistance():Number { return _max; }
+		public function set maxDistance(d:Number):void { _max = d; }
+		
+		/** The minumum effective distance over which forces are exerted.
+		 * 	Any lesser distances will be treated as the minimum. */
+		public function get minDistance():Number { return _min; }
+		public function set minDistance(d:Number):void { _min = d; }
+		
+		// --------------------------------------------------------------------
+		
+		/**
+		 * Creates a new NBodyForce with given parameters.
+		 * @param g the gravitational constant to use.
+		 *  Negative values produce a repulsive force.
+		 * @param maxd a maximum distance over which the force should operate.
+		 *  Particles separated by more than this distance will not interact.
+		 * @param mind the minimum distance over which the force should operate.
+		 *  Particles closer than this distance will interact as if they were
+		 *  the minimum distance apart. This helps avoid extreme forces.
+		 *  Helpful when particles are very close together.
+		 * @param eps an epsilon values for determining a minimum distance
+		 *  between particles
+		 * @param t the theta parameter for the Barnes-Hut approximation.
+		 *  Determines the level of approximation (default value if 0.9).
+		 */
+		public function NBodyForce(g:Number=-1, max:Number=200, min:Number=2,
+								   eps:Number=0.01, t:Number=0.9)
+		{
+			_g = g;
+			_max = max;
+			_min = min;
+			_eps = eps;
+			_t = t;
+			_root = QuadTreeNode.node();
+		}
+
+		/**
+		 * Applies this force to a simulation.
+		 * @param sim the Simulation to apply the force to
+		 */
+		public function apply(sim:Simulation):void
+		{
+			if (_g == 0) return;
+			
+			// clear the quadtree
+			clear(_root); _root = QuadTreeNode.node();
+			
+			// get the tree bounds
+			bounds(sim);
+        
+        	// populate the tree
+        	for (var i:uint = 0; i<sim.particles.length; ++i) {
+        		insert(sim.particles[i], _root, _x1, _y1, _x2, _y2);
+        	}	
+        	
+        	// traverse tree to compute mass
+        	accumulate(_root);
+        	
+        	// calculate forces on each particle
+        	for (i=0; i<sim.particles.length; ++i) {
+        		forces(sim.particles[i], _root, _x1, _y1, _x2, _y2);
+        	}
+		}
+		
+		private function accumulate(n:QuadTreeNode):void {
+			var xc:Number = 0, yc:Number = 0;
+			n.mass = 0;
+			
+			// accumulate childrens' mass
+			var recurse:Function = function(c:QuadTreeNode):void {
+				if (c == null) return;
+				accumulate(c);
+				n.mass += c.mass;
+				xc += c.mass * c.cx;
+				yc += c.mass * c.cy;
+			}
+			if (n.hasChildren) {
+				recurse(n.c1); recurse(n.c2); recurse(n.c3); recurse(n.c4);
+			}
+			
+			// accumulate own mass
+			if (n.p != null) {
+				n.mass += n.p.mass;
+				xc += n.p.mass * n.p.x;
+				yc += n.p.mass * n.p.y;
+			}
+			n.cx = xc / n.mass;
+			n.cy = yc / n.mass;
+		}
+		
+		private function forces(p:Particle, n:QuadTreeNode,
+			x1:Number, y1:Number, x2:Number, y2:Number):void
+		{
+			var f:Number = 0;
+			var dx:Number = n.cx - p.x;
+			var dy:Number = n.cy - p.y;
+			var dd:Number = Math.sqrt(dx*dx + dy*dy);
+			var max:Boolean = _max > 0 && dd > _max;
+			if (dd==0) { // add direction when needed
+				dx = _eps * (0.5-Math.random());
+				dy = _eps * (0.5-Math.random());
+			}
+			
+			// the Barnes-Hut approximation criteria is if the ratio of the
+        	// size of the quadtree box to the distance between the point and
+        	// the box's center of mass is beneath some threshold theta.
+        	if ( (!n.hasChildren && n.p != p) || ((x2-x1)/dd < _t) )
+        	{
+            	if ( max ) return;
+            	// either only 1 particle or we meet criteria
+            	// for Barnes-Hut approximation, so calc force
+            	dd = dd<_min ? _min : dd;
+            	f = _g * p.mass * n.mass / (dd*dd*dd)
+            	p.fx += f*dx; p.fy += f*dy;
+        	}
+        	else if ( n.hasChildren )
+        	{
+            	// recurse for more accurate calculation
+            	var sx:Number = (x1+x2)/2
+            	var sy:Number = (y1+y2)/2;
+            	
+            	if (n.c1) forces(p, n.c1, x1, y1, sx, sy);
+				if (n.c2) forces(p, n.c2, sx, y1, x2, sy);
+				if (n.c3) forces(p, n.c3, x1, sy, sx, y2);
+				if (n.c4) forces(p, n.c4, sx, sy, x2, y2);
+
+            	if ( max ) return;
+            	if ( n.p != null && n.p != p ) {
+            		dd = dd<_min ? _min : dd;
+                	f = _g * p.mass * n.p.mass / (dd*dd*dd);
+                	p.fx += f*dx; p.fy += f*dy;
+            	}
+			}
+		}
+				
+		// -- Helpers ---------------------------------------------------------
+		
+		private function insert(p:Particle, n:QuadTreeNode,
+			x1:Number, y1:Number, x2:Number, y2:Number):void
+		{
+			// ignore particles with NaN coordinates
+			if (isNaN(p.x) || isNaN(p.y)) return;
+			
+			// try to insert particle p at node n in the quadtree
+        	// by construction, each leaf will contain either 1 or 0 particles
+        	if ( n.hasChildren ) {
+            	// n contains more than 1 particle
+            	insertHelper(p,n,x1,y1,x2,y2);
+        	} else if ( n.p != null ) {
+            	// n contains 1 particle
+            	if ( isSameLocation(n.p, p) ) {
+            		// recurse
+                	insertHelper(p,n,x1,y1,x2,y2);
+            	} else {
+            		// divide
+            		var v:Particle = n.p; n.p = null;
+                	insertHelper(v,n,x1,y1,x2,y2);
+                	insertHelper(p,n,x1,y1,x2,y2);
+            	}
+        	} else { 
+            	// n is empty, add p as leaf
+            	n.p = p;
+        	}
+		}
+		
+		private function insertHelper(p:Particle, n:QuadTreeNode, 
+			x1:Number, y1:Number, x2:Number, y2:Number):void
+    	{
+    		// determine split
+			var sx:Number = (x1+x2)/2;
+			var sy:Number = (y1+y2)/2;
+			var c:uint = (p.x >= sx ? 1 : 0) + (p.y >= sy ? 2 : 0);
+			
+			// update bounds
+			if (c==1 || c==3) x1 = sx; else x2 = sx;
+			if (c>1) y1 = sy; else y2 = sy;
+			
+			// update children
+			var cn:QuadTreeNode;
+			if (c == 0) {
+				if (n.c1==null) n.c1 = QuadTreeNode.node();
+				cn = n.c1;
+			} else if (c == 1) {
+				if (n.c2==null) n.c2 = QuadTreeNode.node();
+				cn = n.c2;
+			} else if (c == 2) {
+				if (n.c3==null) n.c3 = QuadTreeNode.node();
+				cn = n.c3;
+			} else {
+				if (n.c4==null) n.c4 = QuadTreeNode.node();
+				cn = n.c4;
+			}
+			n.hasChildren = true;
+			insert(p,cn,x1,y1,x2,y2);
+    	}
+		
+		private function clear(n:QuadTreeNode):void
+		{
+			if (n.c1 != null) clear(n.c1);
+			if (n.c2 != null) clear(n.c2);
+			if (n.c3 != null) clear(n.c3);
+			if (n.c4 != null) clear(n.c4);
+			QuadTreeNode.reclaim(n);
+		}
+		
+		private function bounds(sim:Simulation):void
+		{
+			var p:Particle, dx:Number, dy:Number;
+			_x1 = _y1 = Number.MAX_VALUE;
+			_x2 = _y2 = Number.MIN_VALUE;
+
+			// get bounding box
+			for (var i:uint = 0; i<sim.particles.length; ++i) {
+				p = sim.particles[i] as Particle;
+				if (p.x < _x1) _x1 = p.x;
+				if (p.y < _y1) _y1 = p.y;
+				if (p.x > _x2) _x2 = p.x;
+				if (p.y > _y2) _y2 = p.y;
+			}
+			
+			// square the box
+			dx = _x2 - _x1;
+			dy = _y2 - _y1;
+			if (dx > dy) {
+				_y2 = _y1 + dx;
+			} else {
+				_x2 = _x1 + dy;
+			}
+		}
+		
+		private function isSameLocation(p1:Particle, p2:Particle):Boolean {
+        	return (Math.abs(p1.x - p2.x) < _eps && 
+        			Math.abs(p1.y - p2.y) < _eps);
+    	}
+		
+	} // end of class NBodyForce
+}
+
+// -- Helper QuadTreeNode class -----------------------------------------------
+
+import gssim.gssimstudio.editor.flare.physics.Particle;
+
+class QuadTreeNode
+{
+	public var mass:Number = 0;
+	public var cx:Number = 0;
+	public var cy:Number = 0;
+	public var p:Particle = null;
+	public var c1:QuadTreeNode = null;
+	public var c2:QuadTreeNode = null;
+	public var c3:QuadTreeNode = null;
+	public var c4:QuadTreeNode = null;
+	public var hasChildren:Boolean = false;
+	
+	// -- Factory ---------------------------------------------------------
+	
+	private static var _nodes:Array = new Array();
+	
+	public static function node():QuadTreeNode {
+		var n:QuadTreeNode;
+		if (_nodes.length > 0) {
+			n = QuadTreeNode(_nodes.pop());
+		} else {
+			n = new QuadTreeNode();
+		}
+		return n;
+	}
+	
+	public static function reclaim(n:QuadTreeNode):void {
+		n.mass = n.cx = n.cy = 0;
+		n.p = null;
+		n.hasChildren = false;
+		n.c1 = n.c2 = n.c3 = n.c4 = null;
+		_nodes.push(n);
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/DragForce.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/DragForce.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/DragForce.as	(revision 15)
@@ -0,0 +1,40 @@
+package gssim.gssimstudio.editor.flare.physics
+{
+	/**
+	 * Force simulating frictional drag forces (e.g., air resistance). For
+	 * each particle, this force applies a drag based on the particles
+	 * velocity (<code>F = a * v</code>, where a is a drag co-efficient and
+	 * v is the velocity of the particle).
+	 */
+	public class DragForce implements IForce
+	{
+		private var _dc:Number;
+		
+		/** The drag co-efficient. */
+		public function get drag():Number { return _dc; }
+		public function set drag(dc:Number):void { _dc = dc; }
+		
+		/**
+		 * Creates a new DragForce with given drag co-efficient.
+		 * @param dc the drag co-efficient.
+		 */
+		public function DragForce(dc:Number=0.1) {
+			_dc = dc;
+		}
+		
+		/**
+		 * Applies this force to a simulation.
+		 * @param sim the Simulation to apply the force to
+		 */
+		public function apply(sim:Simulation):void
+		{
+			if (_dc == 0) return;
+			for (var i:uint = 0; i<sim.particles.length; ++i) {
+				var p:Particle = sim.particles[i];
+				p.fx -= _dc * p.vx;
+				p.fy -= _dc * p.vy;
+			}
+		}
+		
+	} // end of class DragForce
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/SpringForce.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/SpringForce.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/SpringForce.as	(revision 15)
@@ -0,0 +1,54 @@
+package gssim.gssimstudio.editor.flare.physics
+{
+	/**
+	 * Force simulating a spring force between two particles. This force
+	 * iterates over each <code>Spring</code> instance in a simulation and
+	 * computes the spring force between the attached particles. Spring forces
+	 * are computed using Hooke's Law plus a damping term modeling frictional
+	 * forces in the spring.
+	 * 
+	 * <p>The actual equation is of the form: <code>F = -k*(d - L) + a*d*(v1 - 
+	 * v2)</code>, where k is the spring tension, d is the distance between
+	 * particles, L is the rest length of the string, a is the damping
+	 * co-efficient, and v1 and v2 are the velocities of the particles.</p>
+	 */
+	public class SpringForce implements IForce
+	{		
+		/**
+		 * Applies this force to a simulation.
+		 * @param sim the Simulation to apply the force to
+		 */
+		public function apply(sim:Simulation):void
+		{
+			var s:Spring, p1:Particle, p2:Particle;
+			var dx:Number, dy:Number, dn:Number, dd:Number, k:Number, fx:Number, fy:Number;
+			
+			for (var i:uint=0; i<sim.springs.length; ++i) {
+				s = Spring(sim.springs[i]);
+				p1 = s.p1;
+				p2 = s.p2;				
+				dx = p1.x - p2.x;
+				dy = p1.y - p2.y;
+				dn = Math.sqrt(dx*dx + dy*dy);
+				dd = dn<1 ? 1 : dn;
+				
+				k  = s.tension * (dn - s.restLength);
+				k += s.damping * (dx*(p1.vx-p2.vx) + dy*(p1.vy-p2.vy)) / dd;
+				k /= dd;
+				
+				// provide a random direction when needed
+				if (dn==0) {
+					dx = 0.01 * (0.5-Math.random());
+					dy = 0.01 * (0.5-Math.random());
+				}
+				
+				fx = -k * dx;
+				fy = -k * dy;
+				
+				p1.fx += fx; p1.fy += fy;
+				p2.fx -= fx; p2.fy -= fy;
+			}
+		}
+		
+	} // end of class SpringForce
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Spring.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Spring.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Spring.as	(revision 15)
@@ -0,0 +1,68 @@
+package gssim.gssimstudio.editor.flare.physics
+{
+	/**
+	 * Represents a Spring in a physics simulation. A spring connects two
+	 * particles and is defined by the springs rest length, spring tension,
+	 * and damping (friction) co-efficient.
+	 */
+	public class Spring
+	{
+		/** The first particle attached to the spring. */
+		public var p1:Particle;
+		/** The second particle attached to the spring. */
+		public var p2:Particle;
+		/** The rest length of the spring. */
+		public var restLength:Number;
+		/** The tension of the spring. */
+		public var tension:Number;
+		/** The damping (friction) co-efficient of the spring. */
+		public var damping:Number;
+		/** Flag indicating that the spring is scheduled for removal. */
+		public var die:Boolean;
+		/** Tag property for storing an arbitrary value. */
+		public var tag:uint;
+		
+		/**
+		 * Creates a new Spring with given parameters.
+		 * @param p1 the first particle attached to the spring
+		 * @param p2 the second particle attached to the spring
+		 * @param restLength the rest length of the spring
+		 * @param tension the tension of the spring
+		 * @param damping the damping (friction) co-efficient of the spring
+		 */
+		public function Spring(p1:Particle, p2:Particle, restLength:Number=10,
+							   tension:Number=0.1, damping:Number=0.1)
+		{
+			init(p1, p2, restLength, tension, damping);
+		}
+		
+		/**
+		 * Initializes an existing spring instance.
+		 * @param p1 the first particle attached to the spring
+		 * @param p2 the second particle attached to the spring
+		 * @param restLength the rest length of the spring
+		 * @param tension the tension of the spring
+		 * @param damping the damping (friction) co-efficient of the spring
+		 */
+		public function init(p1:Particle, p2:Particle, restLength:Number=10,
+							 tension:Number=0.1, damping:Number=0.1):void
+		{
+			this.p1 = p1;
+			this.p2 = p2;
+			this.restLength = restLength;
+			this.tension = tension;
+			this.damping = damping;
+			this.die = false;
+			this.tag = 0;
+		}
+		
+		/**
+		 * "Kills" this spring, scheduling it for removal in the next
+		 * simulation cycle.
+		 */
+		public function kill():void {
+			this.die = true;
+		}
+		
+	} // end of class Spring
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Particle.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Particle.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Particle.as	(revision 15)
@@ -0,0 +1,90 @@
+package gssim.gssimstudio.editor.flare.physics
+{
+	/**
+	 * Represents a Particle in a physics simulation. A particle is a 
+	 * point-mass (or point-charge) subject to physical forces.
+	 */
+	public class Particle
+	{
+		/** The mass (or charge) of the particle. */
+		public var mass:Number;
+		/** The number of springs (degree) attached to this particle. */
+		public var degree:Number;
+		/** The x position of the particle. */
+		public var x:Number;
+		/** The y position of the particle. */
+		public var y:Number;
+		/** The x velocity of the particle. */
+		public var vx:Number;
+		/** A temporary x velocity variable. */
+		public var _vx:Number;
+		/** The y velocity of the particle. */
+		public var vy:Number;
+		/** A temporary y velocity variable. */
+		public var _vy:Number;
+		/** The x force exerted on the particle. */
+		public var fx:Number;
+		/** The y force exerted on the particle. */
+		public var fy:Number;
+		/** The age of the particle in simulation ticks. */
+		public var age:Number;
+		/** Flag indicating if the particule should have a fixed position. */
+		public var fixed:Boolean;
+		/** Flag indicating that the particle is scheduled for removal. */
+		public var die:Boolean;
+		/** Tag property for storing an arbitrary value. */
+		public var tag:uint;
+		
+		/**
+		 * Creates a new Particle with given parameters.
+		 * @param mass the mass (or charge) of the particle
+		 * @param x the x position of the particle
+		 * @param y the y position of the particle
+		 * @param vx the x velocity of the particle
+		 * @param vy the y velocity of the particle
+		 * @param fixed flag indicating if the particle should have a 
+		 *  fixed position
+		 */
+		public function Particle(mass:Number=1, x:Number=0, y:Number=0,
+								 vx:Number=0, vy:Number=0, fixed:Boolean=false)
+		{
+			init(mass, x, y, vx, vy, fixed);
+		}
+		
+		/**
+		 * Initializes an existing particle instance.
+		 * @param mass the mass (or charge) of the particle
+		 * @param x the x position of the particle
+		 * @param y the y position of the particle
+		 * @param vx the x velocity of the particle
+		 * @param vy the y velocity of the particle
+		 * @param fixed flag indicating if the particle should have a 
+		 *  fixed position
+		 */
+		public function init(mass:Number=1, x:Number=0, y:Number=0,
+			vx:Number=0, vy:Number=0, fixed:Boolean=false):void
+		{
+			this.mass = mass;
+			this.degree = 0;
+			this.x = x;
+			this.y = y;
+			this.vx = this._vx = vx;
+			this.vy = this._vy = vy;
+			this.fx = 0;
+			this.fy = 0;
+			this.age = 0;
+			this.fixed = fixed;
+			this.die = false;
+			this.tag = 0;
+		}
+		
+		/**
+		 * "Kills" this particle, scheduling it for removal in the next
+		 * simulation cycle.
+		 */
+		public function kill():void {
+			this.die = true;
+		}
+		
+	} // end of class Particle
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/GravityForce.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/GravityForce.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/GravityForce.as	(revision 15)
@@ -0,0 +1,46 @@
+package gssim.gssimstudio.editor.flare.physics
+{
+	/**
+	 * Force simulating a global gravitational pull on Particle instances.
+	 */
+	public class GravityForce implements IForce
+	{
+		private var _gx:Number;
+		private var _gy:Number;
+		
+		/** The gravitational acceleration in the horizontal dimension. */
+		public function get gravityX():Number { return _gx; }
+		public function set gravityX(gx:Number):void { _gx = gx; }
+		
+		/** The gravitational acceleration in the vertical dimension. */
+		public function get gravityY():Number { return _gy; }
+		public function set gravityY(gy:Number):void { _gy = gy; }
+		
+		/**
+		 * Creates a new gravity force with given acceleration values.
+		 * @param gx the gravitational acceleration in the horizontal dimension
+		 * @param gy the gravitational acceleration in the vertical dimension
+		 */
+		public function GravityForce(gx:Number=0, gy:Number=0) {
+			_gx = gx;
+			_gy = gy;
+		}
+		
+		/**
+		 * Applies this force to a simulation.
+		 * @param sim the Simulation to apply the force to
+		 */
+		public function apply(sim:Simulation):void
+		{
+			if (_gx == 0 && _gy == 0) return;
+			
+			var p:Particle;
+			for (var i:uint=0; i<sim.particles.length; ++i) {
+				p = sim.particles[i];
+				p.fx += _gx * p.mass;
+				p.fy += _gy * p.mass;
+			}
+		}
+		
+	} // end of class GravityForce
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Simulation.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Simulation.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/Simulation.as	(revision 15)
@@ -0,0 +1,342 @@
+package gssim.gssimstudio.editor.flare.physics
+{
+	import flash.geom.Rectangle;
+	
+	/**
+	 * A physical simulation involving particles, springs, and forces.
+	 * Useful for simulating a range of physical effects or layouts.
+	 */
+	public class Simulation
+	{
+		private var _particles:Array = new Array();
+		private var _springs:Array = new Array();
+		private var _forces:Array = new Array();
+		private var _bounds:Rectangle = null;
+		
+		/** The default gravity force for this simulation. */
+		public function get gravityForce():GravityForce {
+			return _forces[0] as GravityForce;
+		}
+		
+		/** The default n-body force for this simulation. */
+		public function get nbodyForce():NBodyForce {
+			return _forces[1] as NBodyForce;
+		}
+		
+		/** The default drag force for this simulation. */
+		public function get dragForce():DragForce {
+			return _forces[2] as DragForce;
+		}
+		
+		/** The default spring force for this simulation. */
+		public function get springForce():SpringForce {
+			return _forces[3] as SpringForce;
+		}
+		
+		/** Sets a bounding box for particles in this simulation.
+		 *  Null (the default) indicates no boundaries. */
+		public function get bounds():Rectangle { return _bounds; }
+		public function set bounds(b:Rectangle):void {
+			if (_bounds == b) return;
+			if (b == null) { _bounds = null; return; }
+			if (_bounds == null) { _bounds = new Rectangle(); }
+			// ensure x is left-most and y is top-most
+			_bounds.x = b.x + (b.width < 0 ? b.width : 0);
+			_bounds.width = (b.width < 0 ? -1 : 1) * b.width;
+			_bounds.y = b.y + (b.width < 0 ? b.height : 0);
+			_bounds.height = (b.height < 0 ? -1 : 1) * b.height;
+		}
+		
+		/**
+		 * Creates a new physics simulation.
+		 * @param gx the gravitational acceleration along the x dimension
+		 * @param gy the gravitational acceleration along the y dimension
+		 * @param drag the default drag (viscosity) co-efficient
+		 * @param attraction the gravitational attraction (or repulsion, for
+		 *  negative values) between particles.
+		 */
+		public function Simulation(gx:Number=0, gy:Number=0,
+			drag:Number=0.1, attraction:Number=-5)
+		{
+			_forces.push(new GravityForce(gx, gy));
+			_forces.push(new NBodyForce(attraction));
+			_forces.push(new DragForce(drag));
+			_forces.push(new SpringForce());
+		}
+		
+		// -- Init Simulation -------------------------------------------------
+		
+		/**
+		 * Adds a custom force to the force simulation.
+		 * @param force the force to add
+		 */
+		public function addForce(force:IForce):void
+		{
+			_forces.push(force);
+		}
+		
+		/**
+		 * Returns the force at the given index.
+		 * @param idx the index of the force to look up
+		 * @return the force at the specified index
+		 */ 
+		public function getForceAt(idx:int):IForce
+		{
+			return _forces[idx];
+		}
+		
+		/**
+		 * Adds a new particle to the simulation.
+		 * @param mass the mass (charge) of the particle
+		 * @param x the particle's starting x position
+		 * @param y the particle's starting y position
+		 * @return the added particle
+		 */
+		public function addParticle(mass:Number, x:Number, y:Number):Particle
+		{
+			var p:Particle = getParticle(mass, x, y);
+			_particles.push(p);
+			return p;
+		}
+		
+		/**
+		 * Removes a particle from the simulation. Any springs attached to
+		 * the particle will also be removed.
+		 * @param idx the index of the particle in the particle list
+		 * @return true if removed, false otherwise.
+		 */
+		public function removeParticle(idx:uint):Boolean
+		{
+			var p:Particle = _particles[idx];
+			if (p == null) return false;
+			
+			// remove springs
+			for (var i:uint = _springs.length; --i >= 0; ) {
+				var s:Spring = _springs[i];
+				if (s.p1 == p || s.p2 == p)
+					removeSpring(i);
+			}
+			// remove from particles
+			reclaimParticle(p);
+			_particles.splice(idx, 1);
+			return true;
+		}
+		
+		/**
+		 * Adds a spring to the simulation
+		 * @param p1 the first particle attached to the spring
+		 * @param p2 the second particle attached to the spring
+		 * @param restLength the rest length of the spring
+		 * @param tension the tension of the spring
+		 * @param damping the damping (friction) co-efficient of the spring
+		 * @return the added spring
+		 */
+		public function addSpring(p1:Particle, p2:Particle, restLength:Number,
+							      tension:Number, damping:Number):Spring
+		{
+			var s:Spring = getSpring(p1, p2, restLength, tension, damping);
+			p1.degree++;
+			p2.degree++;
+			_springs.push(s);
+			return s;
+		}
+		
+		
+		/**
+		 * Removes a spring from the simulation.
+		 * @param idx the index of the spring in the spring list
+		 * @return true if removed, false otherwise
+		 */
+		public function removeSpring(idx:uint):Boolean
+		{
+			if (idx >= _springs.length) return false;
+			var s:Spring = _springs[idx];
+			s.p1.degree--;
+			s.p2.degree--;
+			reclaimSpring(s);
+			_springs.splice(idx, 1);
+			return true;
+		}
+		
+		/**
+		 * Returns the particle list. This is the same array instance backing
+		 * the simulation, so edit the array with caution.
+		 * @return the particle list
+		 */
+		public function get particles():Array {
+			return _particles;
+		}
+		
+		/**
+		 * Returns the spring list. This is the same array instance backing
+		 * the simulation, so edit the array with caution.
+		 * @return the spring list
+		 */
+		public function get springs():Array {
+			return _springs;
+		}
+		
+		// -- Run Simulation --------------------------------------------------
+		
+		/**
+		 * Advance the simulation for the specified time interval.
+		 * @param dt the time interval to step the simulation (default 1)
+		 */
+		public function tick(dt:Number=1):void
+		{	
+			var p:Particle, s:Spring, i:uint, ax:Number, ay:Number;
+			var dt1:Number = dt/2, dt2:Number = dt*dt/2;
+			
+			// remove springs connected to dead particles
+			for (i=_springs.length; --i>=0;) {
+				s = _springs[i];
+				if (s.die || s.p1.die || s.p2.die) {
+					s.p1.degree--;
+					s.p2.degree--;
+					reclaimSpring(s);
+					_springs.splice(i, 1);
+				}
+			}
+			
+			// update particles using Verlet integration
+			for (i=_particles.length; --i>=0;) {
+				p = _particles[i];
+				p.age += dt;
+				if (p.die) { // remove dead particles
+					reclaimParticle(p);
+					_particles.splice(i, 1);
+				} else if (p.fixed) {
+					p.vx = p.vy = 0;
+				} else {
+					ax = p.fx / p.mass; ay = p.fy / p.mass;
+					p.x  += p.vx*dt + ax*dt2;
+					p.y  += p.vy*dt + ay*dt2;
+					p._vx = p.vx + ax*dt1;
+					p._vy = p.vy + ay*dt1;
+				}
+			}
+			// evaluate the forces
+			eval();
+			// update particle velocities
+			for (i=_particles.length; --i>=0;) {
+				p = _particles[i];
+				if (!p.fixed) {
+					ax = dt1 / p.mass;
+					p.vx = p._vx + p.fx * ax;
+					p.vy = p._vy + p.fy * ax;
+				}
+			}
+			
+			// enfore bounds
+			if (_bounds) enforceBounds();
+		}
+		
+		private function enforceBounds():void {
+			var minX:Number = _bounds.x;
+			var maxX:Number = _bounds.x + _bounds.width;
+			var minY:Number = _bounds.y;
+			var maxY:Number = _bounds.y + _bounds.height;
+			
+			for each (var p:Particle in _particles) {
+				if (p.x < minX) {
+					p.x = minX; p.vx = 0;
+				} else if (p.x > maxX) {
+					p.x = maxX; p.vx = 0;
+				}
+				if (p.y < minY) {
+					p.y = minY; p.vy = 0;
+				}
+				else if (p.y > maxY) {
+					p.y = maxY; p.vy = 0;
+				}
+			}
+		}
+		
+		/**
+		 * Evaluates the set of forces in the simulation.
+		 */
+		public function eval():void {
+			var i:uint, p:Particle;
+			// reset forces
+			for (i=_particles.length; --i >= 0; ) {
+				p = _particles[i];
+				p.fx = p.fy = 0;
+			}
+			// collect forces
+			for (i=0; i<_forces.length; ++i) {
+				IForce(_forces[i]).apply(this);
+			}
+		}
+		
+		// -- Particle Pool ---------------------------------------------------
+		
+		/** The maximum number of items stored in a simulation object pool. */
+		public static var objectPoolLimit:int = 5000;
+		protected static var _ppool:Array = new Array();
+		protected static var _spool:Array = new Array();
+		
+		/**
+		 * Returns a particle instance, pulling a recycled particle from the
+		 * object pool if available.
+		 * @param mass the mass (charge) of the particle
+		 * @param x the particle's starting x position
+		 * @param y the particle's starting y position
+		 * @return a particle instance
+		 */
+		protected static function getParticle(mass:Number, x:Number, y:Number):Particle
+		{
+			if (_ppool.length > 0) {
+				var p:Particle = _ppool.pop();
+				p.init(mass, x, y);
+				return p;
+			} else {
+				return new Particle(mass, x, y);
+			}
+		}
+		
+		/**
+		 * Returns a spring instance, pulling a recycled spring from the
+		 * object pool if available.
+		 * @param p1 the first particle attached to the spring
+		 * @param p2 the second particle attached to the spring
+		 * @param restLength the rest length of the spring
+		 * @param tension the tension of the spring
+		 * @param damping the damping (friction) co-efficient of the spring
+		 * @return a spring instance
+		 */
+		protected static function getSpring(p1:Particle, p2:Particle,
+			restLength:Number, tension:Number, damping:Number):Spring
+		{
+			if (_spool.length > 0) {
+				var s:Spring = _spool.pop();
+				s.init(p1, p2, restLength, tension, damping);
+				return s;
+			} else {
+				return new Spring(p1, p2, restLength, tension, damping);
+			}
+		}
+		
+		/**
+		 * Reclaims a particle, adding it to the object pool for recycling
+		 * @param p the particle to reclaim
+		 */
+		protected static function reclaimParticle(p:Particle):void
+		{
+			if (_ppool.length < objectPoolLimit) {
+				_ppool.push(p);
+			}
+		}
+		
+		/**
+		 * Reclaims a spring, adding it to the object pool for recycling
+		 * @param s the spring to reclaim
+		 */
+		protected static function reclaimSpring(s:Spring):void
+		{
+			if (_spool.length < objectPoolLimit) {
+				_spool.push(s);
+			}
+		}
+		
+	} // end of class Simulation
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/IForce.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/IForce.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/flare/physics/IForce.as	(revision 15)
@@ -0,0 +1,15 @@
+package gssim.gssimstudio.editor.flare.physics
+{
+	/**
+	 * Interface representing a force within a physics simulation.
+	 */
+	public interface IForce
+	{
+		/**
+		 * Applies this force to a simulation.
+		 * @param sim the Simulation to apply the force to
+		 */
+		function apply(sim:Simulation):void;
+		
+	} // end of interface IForce
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ExtendedConfiguration.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ExtendedConfiguration.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ExtendedConfiguration.as	(revision 15)
@@ -0,0 +1,20 @@
+package gssim.gssimstudio.editor
+{
+ import mx.collections.ArrayCollection;
+ import gssim.gssimstudio.db.dao.data.Configuration;
+ import gssim.gssimstudio.db.dao.data.User;
+
+ [Bindable]
+ [RemoteClass(alias = "gssim.gssimstudio.flex.app.editor.ExtendedConfiguration")]
+ public class ExtendedConfiguration {
+
+ public function ExtendedConfiguration() {
+    }
+
+ public var configuration:Number;
+ public var networkTopology:String;
+
+ public var blobPropertyList:ArrayCollection;
+ public var textPropertyList:ArrayCollection;
+ }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ScheduleViewerTest.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ScheduleViewerTest.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/ScheduleViewerTest.mxml	(revision 15)
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Application
+	xmlns:mx="http://www.adobe.com/2006/mxml"
+	xmlns:doc="com.daveoncode.ui.*"
+	layout="vertical"
+	horizontalAlign="left"
+	paddingLeft="5"
+	paddingTop="5"
+	creationComplete="application1_creationCompleteHandler(event)"
+	verticalGap="20" xmlns:ui="gssim.gssimstudio.editor.script.com.daveoncode.ui.*" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+	
+	<mx:Script>
+		<![CDATA[
+			import mx.controls.Button;
+			import mx.controls.Image;
+			import mx.events.FlexEvent;
+
+			protected function application1_creationCompleteHandler(event:FlexEvent):void
+			{
+				var img : Image = img1;
+				img.x = 0;
+				img.y = 0;
+				this.removeChild(img1);
+				mimg.addImage(img);
+				var img : Image = img2;
+				img.x = img1.width;
+				img.y = 0;
+				this.removeChild(img2);
+				mimg.addImage(img);
+				var img : Image = img3;
+				img.x = img1.width;
+				img.y = img1.height;
+				this.removeChild(img3);
+				mimg.addImage(img);
+				var img : Image = img4;
+				img.x = 0;
+				img.y = img1.height;
+				this.removeChild(img4);
+				mimg.addImage(img);
+				nav.container = mimg;
+			}
+
+		]]>
+	</mx:Script>
+	
+	<mx:Image source="assets/gannt.png" id="img1"/>
+	<mx:Image source="assets/gannt.png" id="img2"/>
+	<mx:Image source="assets/gannt.png" id="img3"/>
+	<mx:Image source="assets/gannt.png" id="img4"/>
+	
+	<mx:HBox>
+	<mx:Canvas width="800" height="500" backgroundColor="white" id="canvas">
+		<components:MultiImageContainer id="mimg" />
+	</mx:Canvas>
+	<components:MultiImageNavigator id="nav" width="300" height="300" />
+	</mx:HBox>
+	
+</mx:Application>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/FedericaNetwork.txt
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/FedericaNetwork.txt	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/FedericaNetwork.txt	(revision 15)
@@ -0,0 +1,55 @@
+12
+Router_PSNC
+Router_CESNET
+Router_DFN
+Router_GARR
+Router_KTH
+Router_HEANet
+Router_SWITCH
+Router_HUNGARNET
+Router_RedIRIS
+Router_I2CAT
+Router_FCCN
+Router_GRNET
+18
+Router_KTH		Router_HEANet		1	300	1500000
+Router_KTH		Router_PSNC		1	300	1500000
+Router_PSNC		Router_DFN		1	300	1500000
+Router_PSNC		Router_GARR		1	300	1500000
+Router_PSNC		Router_CESNET		1	300	1500000
+Router_DFN		Router_GARR		1	300	1500000
+Router_DFN		Router_CESNET		1	300	1500000
+Router_DFN		Router_SWITCH		1	300	1500000
+Router_GARR		Router_CESNET		1	300	1500000
+Router_GARR		Router_RedIRIS		1	300	1500000
+Router_CESNET		Router_GRNET		1	300	1500000
+Router_GRNET		Router_HUNGARNET		1	300	1500000
+Router_GRNET		Router_RedIRIS		1	300	1500000
+Router_HUNGARNET		Router_SWITCH		1	300	1500000
+Router_RedIRIS		Router_I2CAT		1	300	1500000
+Router_RedIRIS		Router_FCCN		1	300	1500000
+Router_RedIRIS		Router_HEANet		1	300	1500000
+Router_SWITCH		Router_HEANet		1	300	1500000
+20
+PSNC-vnServer1		Router_PSNC		1	300	1500000
+PSNC-vnServer2		Router_PSNC		1	300	1500000
+PSNC-router		Router_PSNC		1	300	1500000
+CESNET-vnServer1		Router_CESNET		1	300	1500000
+CESNET-vnServer2		Router_CESNET		1	300	1500000
+CESNET-router		Router_CESNET		1	300	1500000
+DFN-vnServer1		Router_DFN		1	300	1500000
+DFN-vnServer2		Router_DFN		1	300	1500000
+DFN-router		Router_DFN		1	300	1500000
+GARR-vnServer1		Router_GARR		1	300	1500000
+GARR-vnServer2		Router_GARR		1	300	1500000
+GARR-router		Router_GARR		1	300	1500000
+KTH-vnServer		Router_KTH		1	300	1500000
+HEANet-vnServer		Router_HEANet		1	300	1500000
+SWITCH-vnServer		Router_SWITCH		1	300	1500000
+HUNGARNET-vnServer		Router_HUNGARNET		1	300	1500000
+RedIRIS-vnServer		Router_RedIRIS		1	300	1500000
+I2CAT-vnServer		Router_I2CAT		1	300	1500000
+FCCN-vnServer		Router_FCCN		1	300	1500000
+GRNET-vnServer		Router_GRNET		1	300	1500000
+1
+BrokerInterfaceEntity Router_PSNC 1     300    1500000
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/PionierNetwork.txt
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/PionierNetwork.txt	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/PionierNetwork.txt	(revision 15)
@@ -0,0 +1,76 @@
+# total number of routers
+25
+# each router name
+Poznan
+Gdansk
+Warszawa
+Wroclaw
+Krakow
+Koszalin
+Szczecin
+GorzowWlkp
+Bydgoszcz
+Torun
+Olsztyn
+Bialystok
+ZielonaGora
+Lodz
+Radom
+Pulawy
+Lublin
+Opole
+Czestochowa
+Gliwice
+Kielce
+Rzeszow
+BielskoBiala
+Katowice
+Zamosc
+
+# total number of connections between routers
+30
+# connections between routers
+Gdansk Koszalin 20 300 1500000
+Gdansk Olsztyn 20 300 1500000
+Opole Gliwice 20 300 1500000
+Koszalin Szczecin 20 300 1500000
+Szczecin GorzowWlkp 20 300 1500000
+Bydgoszcz Torun 20 300 1500000
+Radom Kielce 20 300 1500000
+BielskoBiala Krakow 20 300 1500000
+Poznan Warszawa 20 300 1500000
+Olsztyn Bialystok 1 600 1500000
+Kielce Krakow 20 300 1500000
+Gliwice Katowice 20 300 1500000
+Wroclaw Opole 20 300 1500000
+Czestochowa Lodz 20 300 1500000
+Rzeszow Krakow 1 600 1500000
+Lublin Zamosc 20 300 1500000
+Czestochowa Katowice 20 300 1500000
+Poznan ZielonaGora 20 300 1500000
+Warszawa Bialystok 20 300 1500000
+Torun Gdansk 20 300 1500000
+Bydgoszcz Poznan 20 300 1500000
+Poznan GorzowWlkp 20 300 1500000
+Lodz Warszawa 20 300 1500000
+Radom Warszawa 20 300 1500000
+Pulawy Radom 20 300 1500000
+Pulawy Lublin 20 300 1500000
+Rzeszow Zamosc 20 300 1500000
+Lodz Poznan 20 300 1500000
+ZielonaGora Wroclaw 20 300 1500000
+BielskoBiala Gliwice 20 300 1500000
+
+# total number of resources
+5
+# connections between resource and router
+PCSS Poznan 20 100 1500000
+WCSS Wroclaw 20 100 1500000
+Cyfronet Krakow 20 100 1500000
+CITASK Gdansk 20 100 1500000
+ICM Warszawa 20 100 1500000
+
+# total number of users
+1
+# connection between user and router
+BrokerInterfaceEntity ZielonaGora 20 200 1500000
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/test.txt
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/test.txt	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/network-samples/test.txt	(revision 15)
@@ -0,0 +1,27 @@
+# total number of routers
+5
+# each router name
+R1
+R2
+R3
+R4
+R5    
+# total number of connections between routers
+5         
+# connections between routers
+R1  R2  0.01     300    1500000
+R2  R5  0.01     300    1500000
+R1  R3  0.01     300    1500000
+R3  R4  0.01     300    1500000
+R4  R5  0.01     300    1500000
+# total number of resources
+4
+# connections between resource and router
+compRes1 R2 0.01     300    1500000
+compRes2 R4 0.01     300    1500000
+compRes2 R1 0.01     300    1500000
+dataRes1 R5 0.01     300    1500000
+# total number of users
+1
+# connection between user and router
+BrokerInterfaceEntity R1 0.01     300    1500000
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudioModel.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudioModel.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/GSSimStudioModel.as	(revision 15)
@@ -0,0 +1,62 @@
+package gssim.gssimstudio.editor
+{
+import flash.events.EventDispatcher;
+import flash.utils.ByteArray;
+
+import gssim.gssimstudio.db.dao.data.Configuration;
+import gssim.gssimstudio.db.dao.data.User;
+import gssim.gssimstudio.editor.charts.ResourceChartModel;
+
+import mx.collections.ArrayCollection;
+
+	[Bindable]
+	[RemoteClass(alias = "gssim.gssimstudio.flex.app.editor.GSSimStudioModel")]
+	public class GSSimStudioModel {
+
+		public function GSSimStudioModel() {
+		}
+
+		private var tellBlazeToLoadThisClass : ResourceChartModel;
+		
+		public var comparisonComponents : Object;
+		public var resourceChartComponents:Object;
+		
+		public var experimentList:ArrayCollection;
+		public var experimentListChanged:Boolean;
+		
+		public var currentExperimentNetworkTopology : ByteArray;
+		
+		public var currentLocationItem:Object;
+		public var linkLocationItemList:ArrayCollection;
+		public var serverLocationItemList:ArrayCollection;
+		public var workloadFileLocationItemList:ArrayCollection;
+		public var topologiesFileLocationItemList:ArrayCollection;
+		public var resourcesFileLocationItemList:ArrayCollection;
+		public var selectedServerIdx : Number;
+		public var errorDescription : String;
+		
+		public var error:String;
+		public var user:User;
+		public var extendedConfiguration:ExtendedConfiguration;
+
+		public var globalPluginList:ArrayCollection;
+		public var localPluginList:ArrayCollection;
+		public var allocationList:ArrayCollection;
+		public var allocationDetailsList:ArrayCollection;
+		public var blobPropertyList:ArrayCollection;
+		public var metaexperimentList:Object;
+		public var experimentStatsList:ArrayCollection;
+		public var queuesList:ArrayCollection;
+		public var reservationList:ArrayCollection;
+		public var reservationDetailsList:ArrayCollection;
+		public var resourceList:ArrayCollection;
+		public var resourceAllTimelineList:ArrayCollection;
+		public var resourceEnTimelineList:ArrayCollection;
+		public var taskList:ArrayCollection;
+		public var textPropertyList:ArrayCollection;
+		public var unitList:ArrayCollection;
+		public var unitAllTimelineList:ArrayCollection;
+		public var unitDetailsList:ArrayCollection;
+		public var unitEnTimelineList:ArrayCollection;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/ExperimentEditor.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/ExperimentEditor.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/ExperimentEditor.mxml	(revision 15)
@@ -0,0 +1,364 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:code="http://code.google.com/p/flexlib/" width="100%" height="100%" xmlns:experiment="gssim.gssimstudio.editor.gssim.editors.experiment.*" xmlns:components="gssim.gssimstudio.editor.gssim.components.*"
+		   >
+
+<mx:Metadata>
+[ResourceBundle("ExperimentEditor")]
+</mx:Metadata>
+
+	<mx:Script>
+		<![CDATA[
+			import flash.events.Event;
+			import flash.net.FileReferenceList;
+			
+			import gssim.gssimstudio.editor.gssim.editors.experiment.WorkloadFastViewWindow;
+			import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+			import gssim.gssimstudio.editor.gssim.experiment.ExperimentProperties;
+			import gssim.gssimstudio.editor.gssim.experiment.FileProxy;
+			import gssim.gssimstudio.editor.gssim.resources.file.resourceReader;
+			import gssim.gssimstudio.editor.gssim.topology.file.topologyReader;
+			import gssim.gssimstudio.editor.gssim.workload.swf.WorkloadSWF;
+			import gssim.gssimstudio.editor.script.utils.ConjunctionArray;
+			import gssim.gssimstudio.editor.script.views.ViewsHelper;
+			import gssim.gssimstudio.editor.views.TopologyEditor;
+			
+			import mx.collections.ArrayCollection;
+			import mx.controls.Alert;
+			import mx.core.IUIComponent;
+			import mx.events.CloseEvent;
+			import mx.events.DragEvent;
+			import mx.managers.DragManager;
+			
+			import org.vinetoolkit.vine.net.events.VineUploadEvent;
+			
+			[Bindable]
+			public var workspaceWorkloadsFileList : ArrayCollection = new ArrayCollection();
+			[Bindable]
+			public var workspaceTopologiesFileList : ArrayCollection = new ArrayCollection();
+			[Bindable]
+			public var workspaceResourcesFileList : ArrayCollection = new ArrayCollection();
+			
+			[Bindable]
+			public var objectCanvas : ObjectCanvas;
+			
+			[Bindable]
+			public var showDebug : Boolean = false;
+			
+			private var isFileTransfering : Boolean = false;
+			
+			[Bindable]
+			public static var experiments : ArrayCollection = new ArrayCollection();
+			
+			/*
+			public function createNewExperiment() : void
+			{
+				var experimentPropertiesWindow : ExperimentPropertiesWindow = new ExperimentPropertiesWindow();
+				mdiCanvas.windowManager.add(experimentPropertiesWindow);
+			}
+			*/
+			
+			public function editExperiment() : void
+			{
+				experimentProperties.loadExperiment(experimentsDG.selectedItem as ExperimentProperties);
+			}
+			
+			public function performExperiment() : void
+			{
+				submitExperiment(removeItem(experimentsDG) as ExperimentProperties);
+			}
+			
+			public function submitExperiment(experiment : ExperimentProperties) : void
+			{
+				if (experimentMetaname.text == null || experimentMetaname.text == "") return;
+				experiment.metaname = experimentMetaname.text;
+				
+				//prepare job description and generate properties file name
+				var propertyFileName : String = experiment.metaname + "_" + experiment.name + ".properties";
+				parentApplication.xml.children().children().children()[1].children()[0] =
+					"input/" + propertyFileName;
+				var jobDescription : String = parentApplication.xml.toXMLString();
+				jobDesc.text = jobDescription;
+				
+				//prepare grms addresses
+				var serviceDN : String = "/C=PL/O=GRID/O=PSNC/CN=grms/elder3.man.poznan.pl";
+				var serviceURL : String = "https://elder3.man.poznan.pl:8443/gridge/services/GrmsJobFactory";
+				
+				parentApplication.service.uploadAndSubmitExperiment
+					(propertyFileName, experiment.toString(), serviceURL, serviceDN, jobDescription);
+			}
+			
+			public function performAllExperiments() : void
+			{
+				if (experimentMetaname.text == null || experimentMetaname.text == "") return;
+				while (experiments.length > 0)
+				{
+					submitExperiment(experiments[0]);
+					experiments.removeItemAt(0);
+				}
+			}
+			
+			public function addNewWorkloadFile() : void
+			{
+				sendFile(updateWorkloadFile);
+			}
+			
+			private function updateWorkloadFile(event : VineUploadEvent) : void
+			{
+				for each (var reference : FileReference in event.fileReferenceList.fileList)
+				{
+					workspaceWorkloadsFileList.addItem(reference.name);
+				}
+				parentApplication.service.allWorkloadFilesUploaded();
+				finishUploading();
+			}
+			
+			public function addNewTopologyFile() : void
+			{
+				sendFile(updateTopologiesFile);
+			}
+			
+			private function updateTopologiesFile(event : VineUploadEvent) : void
+			{
+				for each (var reference : FileReference in event.fileReferenceList.fileList)
+				{
+					workspaceTopologiesFileList.addItem(reference.name);
+				}
+				parentApplication.service.allTopologiesFilesUploaded();
+				finishUploading();
+			}
+			
+			public function addNewResourceFile() : void
+			{
+				sendFile(updateResourceFile);
+			}
+			
+			private function updateResourceFile(event : VineUploadEvent) : void
+			{
+				for each (var reference : FileReference in event.fileReferenceList.fileList)
+				{
+					workspaceResourcesFileList.addItem(reference.name);
+				}
+				parentApplication.service.allResourcesFilesUploaded();
+				finishUploading();
+			}
+			
+			public function removeItem(datagrid : DataGrid) : Object
+			{
+				var obj : Object = datagrid.selectedItem;
+				(datagrid.dataProvider as ArrayCollection).removeItemAt(datagrid.selectedIndex);
+				return obj;
+			}
+			
+			public function clear(datagrid : DataGrid) : void
+			{
+				(datagrid.dataProvider as ArrayCollection).removeAll();
+			}
+			
+			public function viewWorkload() : void
+			{
+				var file : FileProxy = workloadFilesDG.selectedItem as FileProxy;
+				if (!file.valid) return;
+				var workloadView : WorkloadFastViewWindow = new WorkloadFastViewWindow();
+				mdiCanvas.windowManager.add(workloadView);
+				workloadView.setWorkload(new WorkloadSWF(file.data));
+			}
+			
+			public function loadTopology() : void
+			{
+				var file : FileProxy = topologyFilesDG.selectedItem as FileProxy;
+				if (!file.valid) return;
+				var reader : topologyReader = new topologyReader(parentApplication.topologyEditor.objectCanvas, false);
+				reader.readFromBinary(file.data);
+			}
+			
+			public function loadResources() : void
+			{
+				var file : FileProxy = resourceFilesDG.selectedItem as FileProxy;
+				if (!file.valid) return;
+				var reader : resourceReader = new resourceReader(parentApplication.topologyEditor.objectCanvas, false);
+				reader.readFromString(file.data);
+			}
+			
+			/*****************
+			 * GRMS3 Methods *
+			 *****************/
+			private function submit() : void
+			{
+				var serviceDN : String = "/C=PL/O=GRID/O=PSNC/CN=grms/elder3.man.poznan.pl";
+				var serviceURL : String = "https://elder3.man.poznan.pl:8443/gridge/services/GrmsJobFactory";
+				parentApplication.service.doSubmitApplication(serviceURL, serviceDN, jobDesc.text);
+			}
+			
+			/*************************
+			 * File Transfer Methods *
+			 *************************/			
+			private function sendFile(uploadResult : Object) : void
+			{
+				if (parentApplication.isFileTransfering) return;
+				parentApplication.isFileTransfering = true;
+				parentApplication.upload(true, true, null, uploadResult, uploadFault, null, uploadCancel);//uploadSelect, uploadStart);
+			}
+			
+			private function uploadFault(event : VineUploadEvent) : void
+			{
+				finishUploading();
+			}
+			
+			private function uploadCancel(event : VineUploadEvent) : void
+			{
+				finishUploading();
+			}
+			
+			private function finishUploading() : void
+			{
+				serverItemList.selectedIndex = parentApplication.gsSimStudioModel.selectedServerIdx;
+				parentApplication.isFileTransfering = false;
+			}
+			
+			private function onServerComboChange(ev:Event):void{
+				var selectedIndex :Number= serverItemList.selectedIndex;
+				var o:Object = null;
+				o = ev.target.selectedItem;
+				parentApplication.service.browseResource(o.url, selectedIndex);
+			}
+
+		]]>
+	</mx:Script>
+	
+	<code:MDICanvas id="mdiCanvas" width="100%" height="100%" backgroundColor="#FFFFFF" backgroundAlpha="0">
+		<mx:VBox paddingLeft="64" width="100%">
+			<mx:VBox width="100%">
+				<mx:DataGrid dataProvider="{experiments}" rowHeight="35" id="experimentsDG" width="1168" >
+					<mx:columns>
+						<mx:DataGridColumn dataField="name" headerText="{resourceManager.getString('ExperimentEditor', 'Name')}"/>
+						<mx:DataGridColumn dataField="runs" headerText="{resourceManager.getString('ExperimentEditor', 'Runs')}"/>
+						<mx:DataGridColumn dataField="global" headerText="{resourceManager.getString('ExperimentEditor', 'GlobalPlugin')}"/>
+						<mx:DataGridColumn dataField="local" headerText="{resourceManager.getString('ExperimentEditor', 'LocalPlugin')}"/>
+						<mx:DataGridColumn dataField="exec" headerText="{resourceManager.getString('ExperimentEditor', 'ExecutionPlugin')}"/>
+						<mx:DataGridColumn dataField="workload" headerText="{resourceManager.getString('ExperimentEditor', 'Workload')}"/>
+						<mx:DataGridColumn dataField="topology" headerText="{resourceManager.getString('ExperimentEditor', 'NetworkTopology')}"/>
+						<mx:DataGridColumn dataField="resources" headerText="{resourceManager.getString('ExperimentEditor', 'ResourceDescription')}"/>
+						<mx:DataGridColumn headerText="{resourceManager.getString('ExperimentEditor', 'Actions')}" width="200">
+							<mx:itemRenderer>
+								<mx:Component>
+									<mx:HBox paddingLeft="4">
+										<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Perform')}" toolTip="{resourceManager.getString('ExperimentEditor', 'PerformTooltip')}" click="outerDocument.performExperiment()" height="30" paddingLeft="8"/>
+										<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Edit')}" toolTip="{resourceManager.getString('ExperimentEditor', 'EditTooltip')}" click="outerDocument.editExperiment()" height="30"/>
+										<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Remove')}" toolTip="{resourceManager.getString('ExperimentEditor', 'RemoveTooltip')}" click="outerDocument.removeItem(outerDocument.experimentsDG)" height="30"/>
+									</mx:HBox>
+								</mx:Component>
+							</mx:itemRenderer>
+						</mx:DataGridColumn>
+					</mx:columns>
+				</mx:DataGrid>
+				<mx:HBox>
+					<!--<mx:Button id="newExperiment" click="createNewExperiment()" toolTip="{resourceManager.getString('ExperimentEditor', 'CreateNewExperiment')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'New')}"/>-->
+					<mx:Button id="performExperiments" click="performAllExperiments()" toolTip="{resourceManager.getString('ExperimentEditor', 'PerformAllTooltip')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'PerformAll')}"/>
+					<mx:HBox>
+						<mx:Label text="{resourceManager.getString('ExperimentEditor', 'Metaname')}"/>
+						<components:QuickTooltipImage height="16" width="16"
+								  toolTip="{resourceManager.getString('Help', 'ExperimentMetaname')}"
+								  source="assets/icon/HelpIcon.png"/>
+						<mx:TextInput id="experimentMetaname" width="250" restrict="0-9a-zA-Z" />
+					</mx:HBox>
+				</mx:HBox>
+			</mx:VBox>
+			<mx:HBox width="100%" height="100%">
+				<mx:TabNavigator height="335" width="510">
+					<mx:HBox label="{resourceManager.getString('ExperimentEditor', 'Workspace')}" paddingLeft="5">
+						<mx:VBox>
+							<mx:Label text="{resourceManager.getString('ExperimentEditor', 'Workload')}"/>
+							<mx:DataGrid dataProvider="{workspaceWorkloadsFileList}" rowHeight="35" id="workloadFilesDG" >
+								<mx:columns>
+									<mx:DataGridColumn dataField="fileName" headerText="Name"/>
+									<mx:DataGridColumn headerText="{resourceManager.getString('ExperimentEditor', 'Actions')}" width="55">
+										<mx:itemRenderer>
+											<mx:Component>
+												<mx:HBox paddingLeft="4">
+													<!--
+													-<mx:Button label="{resourceManager.getString('ExperimentEditor', 'View')}" toolTip="{resourceManager.getString('ExperimentEditor', 'ViewTooltip')}" click="outerDocument.viewWorkload()" height="30" paddingLeft="8"/>
+													-->
+													<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Remove')}" toolTip="{resourceManager.getString('ExperimentEditor', 'RemoveTooltip')}" click="outerDocument.removeItem(outerDocument.workloadFilesDG)" height="30"/>
+												</mx:HBox>
+											</mx:Component>
+										</mx:itemRenderer>
+									</mx:DataGridColumn>
+								</mx:columns>
+							</mx:DataGrid>
+							<mx:HBox>
+								<mx:Button id="newWorkloadFile" click="addNewWorkloadFile()" toolTip="{resourceManager.getString('ExperimentEditor', 'AddFile')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Upload')}"/>
+								<mx:Button click="clear(workloadFilesDG)" toolTip="{resourceManager.getString('ExperimentEditor', 'ClearFiles')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Clear')}"/>
+							</mx:HBox>
+						</mx:VBox>
+						<mx:VBox>
+							<mx:Label text="{resourceManager.getString('ExperimentEditor', 'NetworkTopology')}"/>
+							<mx:DataGrid dataProvider="{workspaceTopologiesFileList}" rowHeight="35" id="topologyFilesDG" >
+								<mx:columns>
+									<mx:DataGridColumn dataField="fileName" headerText="Name"/>
+									<mx:DataGridColumn headerText="{resourceManager.getString('ExperimentEditor', 'Actions')}" width="55">
+										<mx:itemRenderer>
+											<mx:Component>
+												<mx:HBox paddingLeft="4">
+													<!--
+													<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Load')}" toolTip="{resourceManager.getString('ExperimentEditor', 'LoadTooltip')}" click="outerDocument.loadTopology()" height="30" paddingLeft="8"/>
+													-->
+													<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Remove')}" toolTip="{resourceManager.getString('ExperimentEditor', 'RemoveTooltip')}" click="outerDocument.removeItem(outerDocument.topologyFilesDG)" height="30"/>
+												</mx:HBox>
+											</mx:Component>
+										</mx:itemRenderer>
+									</mx:DataGridColumn>
+								</mx:columns>
+							</mx:DataGrid>
+							<mx:HBox>
+								<mx:Button id="newTopologyFile" click="addNewTopologyFile()" toolTip="{resourceManager.getString('ExperimentEditor', 'AddFile')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Upload')}"/>
+								<mx:Button click="clear(topologyFilesDG)" toolTip="{resourceManager.getString('ExperimentEditor', 'ClearFiles')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Clear')}"/>
+							</mx:HBox>
+						</mx:VBox>
+						<mx:VBox>
+							<mx:Label text="{resourceManager.getString('ExperimentEditor', 'ResourceDescription')}"/>
+							<!--<mx:DataGrid dataProvider="{resourceFiles}" rowHeight="35" id="resourceFilesDG" >-->
+							<mx:DataGrid dataProvider="{workspaceResourcesFileList}" rowHeight="35" id="resourceFilesDG" >
+								<mx:columns>
+									<mx:DataGridColumn dataField="fileName" headerText="Name"/>
+									<mx:DataGridColumn headerText="{resourceManager.getString('ExperimentEditor', 'Actions')}" width="55">
+										<mx:itemRenderer>
+											<mx:Component>
+												<mx:HBox paddingLeft="4">
+													<!--
+													<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Load')}" toolTip="{resourceManager.getString('ExperimentEditor', 'LoadTooltip')}" click="outerDocument.loadResources()" height="30" paddingLeft="8"/>
+													-->
+													<mx:Button label="{resourceManager.getString('ExperimentEditor', 'Remove')}" toolTip="{resourceManager.getString('ExperimentEditor', 'RemoveTooltip')}" click="outerDocument.removeItem(outerDocument.resourceFilesDG)" height="30"/>
+												</mx:HBox>
+											</mx:Component>
+										</mx:itemRenderer>
+									</mx:DataGridColumn>
+								</mx:columns>
+							</mx:DataGrid>
+							<mx:HBox>
+								<mx:Button id="newResourceFile" click="addNewResourceFile()" toolTip="{resourceManager.getString('ExperimentEditor', 'AddFile')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Upload')}"/>
+								<mx:Button click="clear(resourceFilesDG)" toolTip="{resourceManager.getString('ExperimentEditor', 'ClearFiles')}" labelPlacement="bottom" label="{resourceManager.getString('ExperimentEditor', 'Clear')}"/>
+							</mx:HBox>
+						</mx:VBox>
+					</mx:HBox>
+				</mx:TabNavigator>
+				<mx:TabNavigator width="650" height="335">
+					<experiment:ExperimentPropertiesPanel id="experimentProperties" paddingLeft="5"/>
+					<experiment:FileManager paddingLeft="5"/>
+				</mx:TabNavigator>
+			</mx:HBox>
+			
+			<mx:VBox visible="{showDebug}" includeInLayout="{showDebug}">
+				<mx:HBox>
+					<mx:VBox>
+						<mx:ComboBox id="serverItemList"
+							dataProvider="{parentApplication.gsSimStudioModel.serverLocationItemList}"
+							width="200" y="150" change="onServerComboChange(event)"
+						/>
+						<mx:TextArea id="jobDesc" text="{parentApplication.xml}" width="400" height="300" y="170" enabled="false"/>
+					</mx:VBox>
+					<mx:TextArea id="propertiesFile" width="400" height="300" y="170" />
+				</mx:HBox>
+			</mx:VBox>
+		</mx:VBox>
+	</code:MDICanvas>
+</mx:Module>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/WorkloadEditor.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/WorkloadEditor.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/WorkloadEditor.mxml	(revision 15)
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
+	xmlns:flexlib="http://code.google.com/p/flexlib/"
+	creationComplete="onCreationComplete();"
+	xmlns:workload="gssim.gssimstudio.editor.gssim.editors.workload.*" xmlns:components="gssim.gssimstudio.editor.gssim.components.*">
+
+<mx:Metadata>
+[ResourceBundle("WorkloadEditor")]
+</mx:Metadata>
+
+<mx:Script>
+	<![CDATA[
+		import gssim.gssimstudio.editor.gssim.experiment.FileProxy;
+		import gssim.gssimstudio.editor.gssim.editors.TreeViewWindow;
+		import gssim.gssimstudio.editor.gssim.errors.AbstractError;
+		import mx.collections.ArrayCollection;
+		import gssim.gssimstudio.editor.gssim.workload.Preference;
+		import gssim.gssimstudio.editor.script.views.ViewsHelper;
+		import gssim.gssimstudio.editor.gssim.editors.workload.ComputingResourceHostParameterWindow;
+		import gssim.gssimstudio.editor.gssim.workload.ComputingResourceHostParameter;
+		import gssim.gssimstudio.editor.gssim.workload.RandParams;
+		import gssim.gssimstudio.editor.gssim.editors.workload.RandParamsWindow;
+		import gssim.gssimstudio.editor.gssim.workload.WorkloadBasic;
+		import gssim.gssimstudio.editor.gssim.WindowManager;
+		import flexlib.mdi.effects.effectsLib.MDIVistaEffects;
+		
+		[Bindable]
+		public static var workload : WorkloadBasic = new WorkloadBasic();
+		
+		/**
+		 * After generating workload it will be stored as file reference here
+		 */
+		public static var generatedWorkload : FileProxy;
+		
+		/**
+		 * Initialize application
+		 */
+		private function onCreationComplete():void
+		{				
+			ViewsHelper.WorkloadCanvas = mdiCanvas;
+			
+			mdiCanvas.effectsLib = flexlib.mdi.effects.effectsLib.MDIVistaEffects;
+			
+			//stage.addEventListener(Event.MOUSE_LEAVE, mouseLeaveEventHandler);
+		}
+		
+		/**
+		 * Open RandParamsWindow
+		 */
+		private function openRandParamsWindow(paramName : String) : void
+		{
+			var window : RandParamsWindow = new RandParamsWindow();
+			window.init(paramName);
+			mdiCanvas.windowManager.add(window);
+		}
+		
+		/**
+		 * Clear the property from workload
+		 */
+		private function clearParam(paramName : String) : void
+		{
+			workload.setProperty(paramName, null);
+		}
+		
+		/**
+		 * Add new CRHP to workload
+		 */
+		private function addCRHP() : void
+		{
+			workload.CRHP.addItem(new ComputingResourceHostParameter("freecpus"));
+		}
+		
+		/**
+		 * Add new preference to workload
+		 */
+		private function addPreference() : void
+		{
+			workload.Prefs.addItem(new Preference());
+		}
+		
+		/**
+		 * Validate workload and add all errors to error list
+		 */
+		public function validateWorkload() : Boolean
+		{
+			var isOk : Boolean = true;
+			//clear error list
+			ErrorList.dataProvider.removeAll();
+			//validate properties
+			for each (var ae : AbstractError in workload.validate()) ErrorList.dataProvider.addItem(ae);
+			if (ErrorList.dataProvider.length != 0) isOk = false;
+			return isOk;
+		}
+		
+		/**
+		 * Set the simulation time property
+		 */
+		private function setSimulationStartTime() : void
+		{
+			if (simulationStartTimeDateInput.selectedDate != null)
+			{
+				workload.setProperty(WorkloadBasic.SimulationStartTime, simulationStartTimeDateInput.selectedDate);
+				workload.getProperty(WorkloadBasic.SimulationStartTime).setHours(simulationStartTimeInput.hour, simulationStartTimeInput.minute, simulationStartTimeInput.second, 0);
+			}
+		}
+		
+		/**
+		 * Handle error clicked by user on the error list
+		 */
+		private function solveError() : void
+		{
+			ErrorList.selectedItem.solve();
+			ErrorList.dataProvider.removeItemAt(ErrorList.selectedIndex);
+		}
+	]]>
+</mx:Script>
+<flexlib:MDICanvas id="mdiCanvas" horizontalScrollPolicy="off" verticalScrollPolicy="off"
+			width="100%" height="100%" backgroundColor="#FFFFFF" backgroundAlpha="0">
+			<mx:HBox x="64" height="100%" width="100%">
+				<workload:MainMenu />
+				<mx:VBox height="100%" width="65%">
+					<mx:TabNavigator paddingLeft="5" height="100%" width="100%">
+						<mx:VBox label="{resourceManager.getString('WorkloadEditor', 'Basic')}" y="50">
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'SimulationStartTime')}" width="150"/>
+								<components:TimePicker id="simulationStartTimeInput" is24Hour="true" showSeconds="true" click="setSimulationStartTime()"
+									hour="{workload.getSimulationStartTime.getHours()}"
+									minute="{workload.getSimulationStartTime.getMinutes()}"
+									second="{workload.getSimulationStartTime.getSeconds()}"/>
+								<mx:DateField id="simulationStartTimeDateInput" change="setSimulationStartTime();" selectedDate="{workload.getSimulationStartTime}"/>
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'JobCount')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.JobCount)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.JobCount)"/>
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'SimulationTime')}" width="150"/>
+								<mx:TextInput width="100" id="simulationTime" change="workload.setProperty(WorkloadBasic.SimulationTime, (simulationTime.text != '' ? Number(simulationTime.text) : null))" restrict="0-9"
+									text="{workload.getProperty(WorkloadBasic.SimulationTime)}" />	
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'TaskCount')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.TaskCount)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.TaskCount)"/>
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'TaskLength')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.TaskLength)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.TaskLength)"/>
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'JobPackageLength')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.JobPackageLength)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.JobPackageLength)"/>
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'JobInterval')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.JobInterval)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.JobInterval)"/>
+							</mx:HBox>
+							<mx:HRule />
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'ExecDuration')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.ExecDuration)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.ExecDuration)"/>
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'PeriodStart')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.PeriodStart)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.PeriodStart)"/>
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'PeriodEnd')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.PeriodEnd)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.PeriodEnd)"/>
+							</mx:HBox>
+							<mx:HBox>
+								<mx:Label text="{resourceManager.getString('WorkloadEditor', 'PeriodDuration')}" width="150"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Edit')}" click="openRandParamsWindow(WorkloadBasic.PeriodDuration)"/>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'Clear')}" click="clearParam(WorkloadBasic.PeriodDuration)"/>
+							</mx:HBox>
+						</mx:VBox>
+						<mx:VBox label="{resourceManager.getString('WorkloadEditor', 'ComputingResourceHostParameters')}" y="50">
+							<mx:HBox>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'AddNewComputingResourceHostParameter')}" click="addCRHP()"/>
+							</mx:HBox>
+							<mx:DataGrid dataProvider="{workload.CRHP}" rowHeight="35" width="100%" height="100%" >
+								<mx:columns>
+									<mx:DataGridColumn dataField="metric" headerText="{resourceManager.getString('WorkloadEditor', 'Metric')}"/>
+									<mx:DataGridColumn itemRenderer="gssim.gssimstudio.editor.gssim.editors.workload.DataGridCHRPButtonsRenderer" headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}"/>
+								</mx:columns>
+							</mx:DataGrid>
+						</mx:VBox>
+						<mx:VBox label="{resourceManager.getString('WorkloadEditor', 'Preferences')}" y="50">
+							<mx:HBox>
+								<mx:Button label="{resourceManager.getString('WorkloadEditor', 'AddNewPreference')}" click="addPreference()"/>
+							</mx:HBox>
+							<mx:DataGrid dataProvider="{workload.Prefs}" rowHeight="35" width="100%" height="100%" >
+								<mx:columns>
+									<mx:DataGridColumn dataField="preferenceType" headerText="{resourceManager.getString('WorkloadEditor', 'Type')}"/>
+									<mx:DataGridColumn itemRenderer="gssim.gssimstudio.editor.gssim.editors.workload.DataGridPrefsButtonsRenderer" headerText="{resourceManager.getString('WorkloadEditor', 'Buttons')}"/>
+								</mx:columns>
+							</mx:DataGrid>
+						</mx:VBox>
+					</mx:TabNavigator>
+					<mx:List id="ErrorList" width="100%" height="25%" labelField="Message" dataProvider="{new ArrayCollection()}" itemClick="solveError()" />
+				</mx:VBox>
+			</mx:HBox>
+</flexlib:MDICanvas>
+</mx:Module>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/ArchiveViewer.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/ArchiveViewer.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/ArchiveViewer.mxml	(revision 15)
@@ -0,0 +1,426 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Module 
+	xmlns:fx="http://ns.adobe.com/mxml/2009"  
+	xmlns:s="library://ns.adobe.com/flex/spark"
+	xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="onCreationComplete();"
+	xmlns:archive="gssim.gssimstudio.editor.gssim.editors.archive.*"
+	width="100%" height="100%" xmlns:code="http://code.google.com/p/flexlib/">
+
+<fx:Metadata>
+[ResourceBundle("ArchiveViewer")]
+</fx:Metadata>
+
+<fx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.gssim.editors.archive.GroupStatisticsWindow;
+			import gssim.gssimstudio.editor.gssim.experiment.ExperimentID;
+			import gssim.gssimstudio.editor.gssim.topology.file.topologyReader;
+			import gssim.gssimstudio.editor.script.views.ViewsHelper;
+			
+			import mx.binding.utils.BindingUtils;
+			import mx.collections.ArrayCollection;
+			import mx.collections.ArrayList;
+			import mx.controls.Alert;
+			import mx.events.CollectionEvent;
+			import mx.events.DragEvent;
+			import mx.events.ListEvent;
+			import mx.messaging.management.Attribute;
+			import mx.rpc.events.ResultEvent;
+			
+			[Bindable]
+			protected var selectedExperiment : Object;
+			
+			public function onCreationComplete() : void
+			{
+				ViewsHelper.ArchiveCanvas = mdiCanvas;
+			}
+			
+			public function showAccumulatedStatsWindow() : void
+			{
+				var array:ArrayCollection = getExperimentNames(true);	
+				var groupStatistics : GroupStatisticsWindow = new GroupStatisticsWindow();
+				groupStatistics.init(array);
+				ViewsHelper.ArchiveCanvas.windowManager.add(groupStatistics);
+			}
+			
+			public function getExperimentNames(selected : Boolean = false) : ArrayCollection
+			{
+				var xList:XMLList;
+				if (selected) xList = xml.group.experiment.(@state == "checked");
+				else xList = xml.group.experiment;
+				var array:ArrayCollection = new ArrayCollection();
+				for (var x:uint=0; x < xList.length(); x++){
+					array.addItem(new ExperimentID(xList[x].@PK, xList[x].@name,
+						(parentApplication.gsSimStudioModel.metaexperimentList != null
+							? parentApplication.gsSimStudioModel.metaexperimentList[xList[x].@folder]
+							: xList[x].@folder)));   
+				}
+				return array;
+			}
+			
+			protected function getSelectedExperiments() : ArrayCollection
+			{
+				var result : ArrayCollection = new ArrayCollection();
+				var xList:XMLList = xml.group.experiment.(@state == "checked");
+				for (var x:uint=0; x < xList.length(); x++){
+					result.addItem(getExperiment(xList[x].@PK, xList[x].@folder));
+				}
+				return result;
+			}
+			
+			protected function getSelectedExperimentsPKs() : ArrayCollection
+			{
+				var result : ArrayCollection = new ArrayCollection();
+				var xList:XMLList = xml.group.experiment.(@state == "checked");
+				for (var x:uint=0; x < xList.length(); x++){
+					result.addItem(parseInt(xList[x].@PK));
+				}
+				return result;
+			}
+			
+			public function moveToFolder() : void
+			{
+				if (moveToFolderInput.text != null && moveToFolderInput.text != "")
+				{
+					parentApplication.service.changeExperimentsMetaexperiment(getSelectedExperimentsPKs(), moveToFolderInput.text);
+				}
+			}
+			
+			public function getExperiments() : void
+			{
+				parentApplication.service.getExperimentsFromDb(null, null, null);
+			}
+
+			public function convertToXml(event : ResultEvent) : void
+			{
+				if (parentApplication.gsSimStudioModel.experimentListChanged == true)
+				{
+					parentApplication.gsSimStudioModel.experimentListChanged = false;
+					var temp : XML = <experiments />;
+					for each (var exp2 : Object in parentApplication.gsSimStudioModel.experimentList)
+					{
+						try
+						{
+							var exp : Object = exp2;
+							var exper : XML = <experiment />;
+							exper.@PK = exp.PK;
+							exper.@folder = exp.metaexpId;
+							exper.@state = "unchecked";
+							exper.@name = exp.name;
+							exper.@published = exp.commissionDate;
+							exper.@status = exp.status;
+							if (!temp.hasOwnProperty("group") || !(temp.group.attribute("id").contains(exp.metaexpId)))
+							{
+								var xmlGroup : XML = <group />;
+								xmlGroup.@state = "unchecked";
+								xmlGroup.@name = parentApplication.gsSimStudioModel.metaexperimentList[exp.metaexpId];
+								xmlGroup.@id = exp.metaexpId;
+								temp.appendChild(xmlGroup);
+							}
+							
+							temp.group.(@id == exp.metaexpId).appendChild(exper);
+						}
+						catch (e : Error)
+						{
+							Alert.show(e.toString() + "\n" + e.message + "\n" + e.name);
+						}
+					}
+					xml = temp;
+				}
+			}
+			
+			public function getExperiment(PK : String, Folder : String) : Object
+			{
+				var metaId : int = parseInt(Folder);
+				for each (var exp : Object in parentApplication.gsSimStudioModel.experimentList)
+				{
+					if (exp.PK.toFixed() == PK && exp.metaexpId == metaId) return exp;
+				}
+				return null;
+			}
+			
+			public function getCurrentExperiment() : Object
+			{
+				selectedExperiment = getExperiment(tree.selectedItem.@PK, tree.selectedItem.@folder); 
+				return selectedExperiment;
+			}
+			
+			protected function experimentSelectionChanged(event:ListEvent):void
+			{
+				experimentData.loadExperiment(getCurrentExperiment());
+			}
+
+		]]>
+</fx:Script>
+	
+	
+<fx:Declarations>
+	<fx:XML id="xml">
+		<experiments>
+			<group name="meta1" state="unchecked">
+				<experiment name="exp1" PK="15" state="unchecked" folder="meta1"/>
+				<experiment name="exp2" PK="25" state="unchecked" folder="meta1"/>
+			</group>
+			<group name="meta2" state="unchecked">
+				<experiment name="exp1" PK="35" state="unchecked" folder="meta2"/>
+				<experiment name="exp2" PK="45" state="unchecked" folder="meta2"/>
+			</group>
+		</experiments>
+	</fx:XML>
+</fx:Declarations>
+	
+	<code:MDICanvas id="mdiCanvas" width="100%" height="100%" backgroundColor="#FFFFFF" backgroundAlpha="0">
+		<s:VGroup paddingLeft="64" width="100%">
+			<mx:HDividedBox width="100%">
+				<mx:AdvancedDataGrid height="100%" width="100%" labelField="@label" id="tree"
+						 itemClick="experimentSelectionChanged(event)"
+						 groupItemRenderer="gssim.gssimstudio.editor.gssim.components.CheckADGRenderer"
+						 >
+					<mx:dataProvider>
+						<mx:HierarchicalCollectionView showRoot="false" >
+							<mx:source>
+								<mx:HierarchicalData source="{xml}"/>
+							</mx:source>
+						</mx:HierarchicalCollectionView>
+					</mx:dataProvider>
+					<mx:columns>
+						<mx:AdvancedDataGridColumn dataField="@name" headerText="{resourceManager.getString('ArchiveViewer', 'Name')}"/>
+						<mx:AdvancedDataGridColumn dataField="@published" headerText="{resourceManager.getString('ArchiveViewer', 'CommissionDate')}"/>
+						<mx:AdvancedDataGridColumn dataField="@status" headerText="{resourceManager.getString('ArchiveViewer', 'Status')}"/>
+						<!--<mx:AdvancedDataGridColumn dataField="@state"/>-->
+					</mx:columns>
+				</mx:AdvancedDataGrid>
+				<archive:ExperimentDataGroup id="experimentData" visible="{selectedExperiment != null}"
+					/>
+			</mx:HDividedBox>
+			<s:Button label="{resourceManager.getString('ArchiveViewer', 'Refresh')}" click="getExperiments()"/>
+			
+			<!--
+			<mx:TabNavigator paddingLeft="5" creationPolicy="all" width="100%">
+				<mx:VBox label="Allocations" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.allocationList}" rowHeight="35" id="allocationsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="PK" headerText="PK"/>
+							<mx:DataGridColumn dataField="taskId" headerText="Task ID"/>
+							<mx:DataGridColumn dataField="unitId" headerText="Unit ID"/>
+							<mx:DataGridColumn dataField="begin" headerText="begin"/>
+							<mx:DataGridColumn dataField="end" headerText="end"/>
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get allocations from DB" click="{parentApplication.service.getAllocationsFromDb(null, null)}"/>
+				</mx:VBox>	
+				
+				<mx:VBox label="Allocation details" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.allocationDetailsList}" rowHeight="35" id="allocationDetailsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fkAllocationId" headerText="Allocation Id"/>
+							<mx:DataGridColumn dataField="name" headerText="Name"/>
+							<mx:DataGridColumn dataField="value" headerText="Value"/>
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get allocation details from DB" click="{parentApplication.service.getAllocationDetailsFromDb(null)}"/>
+				</mx:VBox>	
+				
+				<mx:VBox label="Configuration" width="100%">
+					<mx:TextArea id="net" text="{parentApplication.gsSimStudioModel.extendedConfiguration.networkTopology}" width="100%" height="100%" editable="false"/>
+					<s:Button label="Get configuration with id 2 from DB" click="{parentApplication.service.getExtendedConfigurationFromDb(2); ln.enabled=true;}"/>
+					<s:Button label="Load the configuration to Network Editor" click="{loadNetwork();}" enabled="false" id="ln"/>
+				</mx:VBox>
+			
+				<mx:VBox label="{resourceManager.getString('ArchiveViewer', 'Experiments')}" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.experimentList}" rowHeight="35" id="experimentsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="PK" headerText="{resourceManager.getString('ArchiveViewer', 'ID')}"/>
+							<mx:DataGridColumn dataField="status" headerText="{resourceManager.getString('ArchiveViewer', 'Status')}"/>
+							<mx:DataGridColumn dataField="commissionDate" headerText="{resourceManager.getString('ArchiveViewer', 'Description')}"/>
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get experiments from DB" click="{parentApplication.service.getExperimentsFromDb(null, null, null)}"/>
+				</mx:VBox>
+			
+				<mx:VBox label="Experiment stats" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.experimentStatsList}" rowHeight="35" id="experimentStatsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="id" headerText="Experiment Id"/>
+							<mx:DataGridColumn dataField="name" headerText="Name"/>
+							<mx:DataGridColumn dataField="value" headerText="Value"/>
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get experiment stats from DB" click="{parentApplication.service.getExperimentStatsFromDb(null)}"/>
+				</mx:VBox>	
+				
+				<mx:VBox label="Queues" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.queuesList}" rowHeight="35" id="queuesDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fkResourceId" headerText="Resource Id"/>
+							<mx:DataGridColumn dataField="name" headerText="Name"/>
+							<mx:DataGridColumn dataField="avgLength" headerText="Avg length"/>
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get queues from DB" click="{parentApplication.service.getQueuesFromDb(null)}"/>
+				</mx:VBox>	
+				
+				
+				<mx:VBox label="Reservations" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.reservationList}" rowHeight="35" id="reservationsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="PK" headerText="PK"/>
+							<mx:DataGridColumn dataField="taskId" headerText="Task Id"/>
+							<mx:DataGridColumn dataField="unitId" headerText="Unit Id"/>
+							<mx:DataGridColumn dataField="begin" headerText="Begin"/>
+							<mx:DataGridColumn dataField="end" headerText="End"/>							
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get reservations from DB" click="{parentApplication.service.getReservationsFromDb(null, null)}"/>
+				</mx:VBox>		
+				
+				<mx:VBox label="Reservation details" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.reservationDetailsList}" rowHeight="35" id="reservationDetailsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fkReservationId" headerText="Reservation Id"/>
+							<mx:DataGridColumn dataField="name" headerText="Name"/>
+							<mx:DataGridColumn dataField="value" headerText="Value"/>						
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get reservations from DB" click="{parentApplication.service.getReservationDetailsFromDb(null)}"/>
+				</mx:VBox>								
+				
+				<mx:VBox label="Resources" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.resourceList}" rowHeight="35" id="resourcesDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="PK" headerText="PK"/>
+							<mx:DataGridColumn dataField="expId" headerText="Experiment Id"/>
+							<mx:DataGridColumn dataField="name" headerText="Name"/>
+							<mx:DataGridColumn dataField="type" headerText="Type"/>
+							<mx:DataGridColumn dataField="allocationLoad" headerText="Allocation load"/>				
+							<mx:DataGridColumn dataField="reservationLoad" headerText="Reservation load"/>
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get resources from DB" click="{parentApplication.service.getResourcesFromDb(null, null, null)}"/>
+				</mx:VBox>								
+			
+				<mx:VBox label="Resource alloctaion timeline" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.resourceAllTimelineList}" rowHeight="35" id="resourceAllTimelinesDetailsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fkResourceId" headerText="Resource Id"/>
+							<mx:DataGridColumn dataField="timestamp" headerText="Timestamp"/>
+							<mx:DataGridColumn dataField="usage" headerText="Usage"/>						
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get resource allocation timeline from DB" click="{parentApplication.service.getResourceAllTimelineFromDb(null, null, null)}"/>
+				</mx:VBox>			
+			
+				<mx:VBox label="Resource energy timeline" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.resourceEnTimelineList}" rowHeight="35" id="resourceEnTimelinesDetailsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fkResourceId" headerText="Resource Id"/>
+							<mx:DataGridColumn dataField="timestamp" headerText="Timestamp"/>
+							<mx:DataGridColumn dataField="usage" headerText="Usage"/>						
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get resource energy timeline from DB" click="{parentApplication.service.getResourceEnTimelineFromDb(null, null, null)}"/>
+				</mx:VBox>										
+				
+				<mx:VBox label="Tasks" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.taskList}" rowHeight="35" id="tasksDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="PK" headerText="PK"/>						
+							<mx:DataGridColumn dataField="expId" headerText="Experiment Id"/>
+							<mx:DataGridColumn dataField="jobId" headerText="Job Id"/>
+							<mx:DataGridColumn dataField="taskId" headerText="Task Id"/>
+							<mx:DataGridColumn dataField="procSetId" headerText="Proceess set Id"/>
+							<mx:DataGridColumn dataField="parentId" headerText="Parent Id"/>
+							<mx:DataGridColumn dataField="execStartDate" headerText="Exec start date"/>
+							<mx:DataGridColumn dataField="execFinishDate" headerText="Exec finish date"/>
+							<mx:DataGridColumn dataField="execEndDate" headerText="Exec end date"/>
+							<mx:DataGridColumn dataField="gbSubmitDate" headerText="Gb submit date"/>
+							<mx:DataGridColumn dataField="lbSubmitDate" headerText="Lb Submit Date"/>
+							<mx:DataGridColumn dataField="completionTime" headerText="Completion Time"/>
+							<mx:DataGridColumn dataField="execStartTime" headerText="Exec start time"/>
+							<mx:DataGridColumn dataField="executionTime" headerText="Execution time"/>
+							<mx:DataGridColumn dataField="startTime" headerText="Start time"/>
+							<mx:DataGridColumn dataField="readyTime" headerText="Ready time"/>
+							<mx:DataGridColumn dataField="flowTime" headerText="Flow time"/>
+							<mx:DataGridColumn dataField="waitingTime" headerText="Waiting time"/>
+							<mx:DataGridColumn dataField="gqWaitingTime" headerText="Gq waiting time"/>
+							<mx:DataGridColumn dataField="lateness" headerText="Lateness"/>
+							<mx:DataGridColumn dataField="tardiness" headerText="Tardiness"/>
+							<mx:DataGridColumn dataField="makespan" headerText="Makespan"/>							
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get tasks from DB" click="{parentApplication.service.getTasksFromDb(null, null, null, null, null)}"/>
+				</mx:VBox>											
+				
+				<mx:VBox label="Text properties" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.textPropertyList}" rowHeight="35" id="textPropertiesDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="configId" headerText="Configuration Id"/>
+							<mx:DataGridColumn dataField="name" headerText="Name"/>
+							<mx:DataGridColumn dataField="value" headerText="Value"/>						
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get text properties from DB" click="{parentApplication.service.getTextPropertiesFromDb(null)}"/>
+				</mx:VBox>				
+				
+				<mx:VBox label="Units" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.unitList}" rowHeight="35" id="unitsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="PK" headerText="PK"/>
+							<mx:DataGridColumn dataField="resourceId" headerText="Resource Id"/>
+							<mx:DataGridColumn dataField="name" headerText="Name"/>
+							<mx:DataGridColumn dataField="type" headerText="Type"/>
+							<mx:DataGridColumn dataField="allocationLoad" headerText="Allocation load"/>				
+							<mx:DataGridColumn dataField="reservationLoad" headerText="Reservation load"/>
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get reservations from DB" click="{parentApplication.service.getUnitsFromDb(null, null, null)}"/>
+				</mx:VBox>	
+				
+				<mx:VBox label="Unit alloctaion timeline" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.unitAllTimelineList}" rowHeight="35" id="unitAllTimelinesDetailsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fkUnitId" headerText="Unit Id"/>
+							<mx:DataGridColumn dataField="timestamp" headerText="Timestamp"/>
+							<mx:DataGridColumn dataField="usage" headerText="Usage"/>						
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get unit allocation timeline from DB" click="{parentApplication.service.getUnitAllTimelineFromDb(null, null, null)}"/>
+				</mx:VBox>	
+
+				<mx:VBox label="Unit details" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.unitDetailsList}" rowHeight="35" id="unitDetailsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fkUnitId" headerText="Unit Id"/>
+							<mx:DataGridColumn dataField="name" headerText="Name"/>
+							<mx:DataGridColumn dataField="value" headerText="Value"/>						
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get units from DB" click="{parentApplication.service.getUnitDetailsFromDb(null)}"/>
+				</mx:VBox>								
+				
+				<mx:VBox label="Unit energy timeline" width="100%">
+					<mx:DataGrid dataProvider="{parentApplication.gsSimStudioModel.unitEnTimelineList}" rowHeight="35" id="unitEnTimelinesDetailsDataGrid" width="100%" >
+						<mx:columns>
+							<mx:DataGridColumn dataField="fkUnitId" headerText="Unit Id"/>
+							<mx:DataGridColumn dataField="timestamp" headerText="Timestamp"/>
+							<mx:DataGridColumn dataField="usage" headerText="Usage"/>						
+						</mx:columns>
+					</mx:DataGrid>
+					<s:Button label="Get unit energy timeline from DB" click="{parentApplication.service.getUnitEnTimelineFromDb(null, null, null)}"/>
+				</mx:VBox>										
+				
+			</mx:TabNavigator>
+			-->
+			
+			<mx:Button id="accumulatedStatsWindow" click="showAccumulatedStatsWindow()" label="View stats"/>
+			<mx:HBox>
+				<s:TextInput id="moveToFolderInput" restrict="0-9a-zA-Z"/>
+				<mx:Button id="moveToFolderButton" click="moveToFolder()" label="{resourceManager.getString('ArchiveViewer', 'Move')}"/>
+			</mx:HBox>
+			
+			<mx:TextArea text="{parentApplication.gsSimStudioModel.error}" width="100%" height="150" editable="false"/>
+
+		</s:VGroup>
+	
+	</code:MDICanvas>
+</mx:Module>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/TopologyEditor.mxml
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/TopologyEditor.mxml	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/views/TopologyEditor.mxml	(revision 15)
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
+	xmlns:flexlib="http://code.google.com/p/flexlib/"
+	
+	xmlns:degrafa="com.degrafa.*"
+	xmlns:geometry="com.degrafa.geometry.*"
+	xmlns:paint="com.degrafa.paint.*"
+	xmlns:skins="com.degrafa.skins.*"
+	xmlns:erno="erno.*"
+	
+	creationComplete="onCreationComplete();"
+	xmlns:ns="sample_content.*" xmlns:gssim="gssim.gssimstudio.editor.gssim.editors.topology.*" xmlns:local="*"
+	xmlns:display="flash.display.*">
+	
+<mx:Metadata>
+[ResourceBundle("TopologyEditor")]
+[ResourceBundle("ResourceEditor")]
+</mx:Metadata>
+
+	<mx:Script>
+		<![CDATA[
+			import gssim.gssimstudio.editor.script.views.ViewsHelper;
+			import gssim.gssimstudio.editor.script.command.ApplyZoomCommand;
+			import gssim.gssimstudio.editor.gssim.experiment.ExperimentProperties;
+			import gssim.gssimstudio.editor.script.event.InvalidActionEvent;
+			import gssim.gssimstudio.editor.script.command.OpenObjectChartListWindowCommand;
+			import mx.events.ResizeEvent;
+			import com.greensock.*;
+			import com.greensock.easing.*;
+			import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+			import gssim.gssimstudio.editor.gssim.topology.file.topologyWriter;
+			import gssim.gssimstudio.editor.script.command.OpenMinimapWindowCommand;
+			import gssim.gssimstudio.editor.script.event.ObjectEvent;
+			import gssim.gssimstudio.editor.script.event.LinkEvent;
+			import gssim.gssimstudio.editor.gssim.topology.file.topologyReader;
+			import gssim.gssimstudio.editor.gssim.topology.GraphItem;
+			import gssim.gssimstudio.editor.gssim.topology.Graph;
+			import gssim.gssimstudio.editor.gssim.editors.topology.NetworkEditorToolbox;
+			import gssim.gssimstudio.editor.gssim.WindowManager;
+			import gssim.gssimstudio.editor.script.command.DoNothing;
+			import gssim.gssimstudio.editor.script.command.OpenToolboxWindowCommand;
+			import gssim.gssimstudio.editor.script.command.OpenLinkPropertiesWindowCommand;
+			import gssim.gssimstudio.editor.script.command.OpenObjectPropertiesWindowCommand;
+			import gssim.gssimstudio.editor.script.command.OpenObjectChartListWindowCommand;
+			import mx.controls.Button;
+			import mx.events.ItemClickEvent;
+			import flash.utils.getTimer;
+			import flexlib.mdi.events.MDIWindowEvent;
+			import flexlib.mdi.effects.effectsLib.MDIVistaEffects;
+			import flexlib.mdi.events.MDIManagerEvent;
+			
+			import mx.controls.Alert;
+			import mx.events.CloseEvent;
+			import mx.events.ListEvent;			
+			
+			import flexlib.mdi.containers.MDIWindow;
+			
+			private var isEditMode : Boolean = true;
+			
+			/**
+			 * Initialize Network Topology Editor, create toolbox and minimap, add event listeners
+			 */
+			private function onCreationComplete():void
+			{
+				ViewsHelper.TopologyCanvas = mdiCanvas;
+				
+				mdiCanvas.effectsLib = flexlib.mdi.effects.effectsLib.MDIVistaEffects;
+								
+				menu.objectCanvas = objectCanvas;
+				menu.mdiCanvas = mdiCanvas;
+				
+				//stage.addEventListener(Event.MOUSE_LEAVE, mouseLeaveEventHandler);
+				
+				var toolbox : OpenToolboxWindowCommand  = new OpenToolboxWindowCommand(mdiCanvas);
+				toolbox.execute();
+				toolbox.init(objectCanvas);
+								
+				var minimap : OpenMinimapWindowCommand = new OpenMinimapWindowCommand(mdiCanvas);
+				minimap.execute();
+				minimap.init(objectCanvas);
+				
+				objectCanvas.addEventListener(ObjectCanvas.LINK_CLICK, linkClickEventHandler);
+				objectCanvas.addEventListener(ObjectCanvas.ROUTER_CLICK, routerClickEventHandler);
+				objectCanvas.addEventListener(ObjectCanvas.OBJECT_MOVED, objectMovedEventHandler);
+				objectCanvas.addEventListener(ObjectCanvas.OBJECT_REMOVED, objectRemovedEventHandler);
+				objectCanvas.addEventListener(ObjectCanvas.CLEANED, canvasCleanedEventHandler);
+				objectCanvas.addEventListener(MouseEvent.MOUSE_WHEEL, mouseZoomOnCanvasEventHandler);
+				objectCanvas.addEventListener(ResizeEvent.RESIZE, canvasResizedEventHandler);
+				objectCanvas.addEventListener(ObjectCanvas.INVALID_ACTION, canvasInvalidActionEventHandler);
+				
+				objectCanvas.empty();
+			}
+			
+			/**
+			 * Handles invalid user action
+			 */
+			private function canvasInvalidActionEventHandler(event : InvalidActionEvent) : void
+			{
+				Alert.show(event.message);
+			}
+			
+			/**
+			 * When canvas size changes the minimap should be rescaled properly
+			 */
+			private function canvasResizedEventHandler(event : Event) : void
+			{
+				var k : OpenMinimapWindowCommand = new OpenMinimapWindowCommand(mdiCanvas);
+				k.scale();
+			}
+			
+			/**
+			 * When canvas is cleaner update minimap 
+			 */
+			private function canvasCleanedEventHandler(event : Event) : void
+			{
+				var k : OpenMinimapWindowCommand = new OpenMinimapWindowCommand(mdiCanvas);
+				k.clean();
+			}
+			
+			/**
+			 * When object is moved on canvas update its position on minimap
+			 */
+			private function objectMovedEventHandler(event : ObjectEvent) : void
+			{
+				var k : OpenMinimapWindowCommand = new OpenMinimapWindowCommand(mdiCanvas);
+				k.update(event.object);
+			}
+			
+			/**
+			 * Object was removed from canvas so remove it from minimap
+			 */
+			private function objectRemovedEventHandler(event : ObjectEvent) : void
+			{
+				var k : OpenMinimapWindowCommand = new OpenMinimapWindowCommand(mdiCanvas);
+				k.update(event.object, true);
+			}
+			
+			/**
+			 * Link was clicked - if current mode is edit mode open link properties window
+			 */
+			private function linkClickEventHandler(event : LinkEvent) : void
+			{
+				if (isEditMode)
+				{
+					var k : OpenLinkPropertiesWindowCommand = new OpenLinkPropertiesWindowCommand(mdiCanvas, event.link);
+					k.execute();
+				}
+			}
+			
+			/**
+			 * Object was clicked - if current mode is edit mode open properties window, else open charts window
+			 */
+			private function routerClickEventHandler(event : ObjectEvent) : void
+			{
+				if (isEditMode)
+				{
+					var properties : OpenObjectPropertiesWindowCommand = new OpenObjectPropertiesWindowCommand(mdiCanvas, event.object);
+					properties.execute();
+				}
+				else
+				{
+					var chartList : OpenObjectChartListWindowCommand = new OpenObjectChartListWindowCommand(mdiCanvas, event.object);
+					chartList.execute();
+				}
+			}
+			
+			/**
+			 * Mouse cursor left application - stop dragging objects
+			 */
+			private function mouseLeaveEventHandler(event : Event) : void
+			{
+				objectCanvas.forceStopDrag(event);
+			}
+				
+			/**
+			 * Zoom canvas based on mouse wheel and mouse position
+			 */
+			private function mouseZoomOnCanvasEventHandler(event : MouseEvent) : void
+			{
+				var k : ApplyZoomCommand = new ApplyZoomCommand(objectCanvas, event.delta, event.stageX, event.stageY);
+				k.execute();
+			}
+			
+		]]>
+	</mx:Script>
+	
+	<flexlib:MDICanvas id="mdiCanvas" horizontalScrollPolicy="off" verticalScrollPolicy="off"
+			width="100%" height="100%" backgroundColor="#FFFFFF" backgroundAlpha="0">
+		<gssim:ObjectCanvas id="objectCanvas" width="100%" height="100%"/>
+		<!--
+		<mx:Button id="modeButton" styleName="modeButton" click="isEditMode = modeButton.selected"
+			toggle="true" width="96" height="96" bottom="24" left="0" selected="true"
+			toolTip="{(modeButton.selected ? resourceManager.getString('TopologyEditor', 'EditMode') : resourceManager.getString('TopologyEditor', 'ViewMode'))}"/>
+		-->
+		<gssim:MainMenu id="menu" x="64" y="0"/>
+	
+	</flexlib:MDICanvas>
+</mx:Module>
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/extendedSlider.css
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/extendedSlider.css	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/extendedSlider.css	(revision 15)
@@ -0,0 +1,4 @@
+.sliderLabel
+{
+	fontSize: 10
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/charts.css
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/charts.css	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/charts.css	(revision 15)
@@ -0,0 +1,48 @@
+.zoomButton 
+{
+	cornerRadius: 20;
+	textAlign: center;
+	paddingLeft: 0;
+	paddingTop: 0;
+	paddingRight: 0;
+	paddingBottom: 0;
+}
+
+.selectionBox 
+{
+	borderStyle : solid;
+	borderColor : #000000;
+	themeColor : #7FFC97;
+	borderThickness : 0;
+	alpha : 1.0;
+	backgroundColor : #56FF3A;
+	backgroundAlpha : 0.17;
+}
+
+.title
+{
+	textAlign: center;
+	fontSize: 14;
+	fontWeight: bold;
+}
+
+.subtitle
+{
+	textAlign: center;
+	fontSize: 11;
+	fontWeight: normal;
+}
+
+.verticalAxisTitle
+{ 
+	fontFamily: myArialFont; 
+	fontSize: 10; 
+	fontWeight: normal;
+} 
+
+.horizontalAxisTitle
+{
+	fontFamily: myArialFont; 
+	fontSize: 10; 
+	fontWeight: normal;
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/experimentWindow.css
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/experimentWindow.css	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/assets/css/experimentWindow.css	(revision 15)
@@ -0,0 +1,4 @@
+Label.importedFileLabel {
+	padding-left: 15px;
+	font-size: 8px;
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/preloader/CustomPreloader.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/preloader/CustomPreloader.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/preloader/CustomPreloader.as	(revision 15)
@@ -0,0 +1,82 @@
+package gssim.gssimstudio.editor.script.preloader
+{
+	import flash.display.Sprite;
+	import flash.events.Event;
+	import flash.events.ProgressEvent;
+	import flash.events.TimerEvent;
+	import flash.utils.Timer;
+	
+	import mx.events.FlexEvent;
+	import mx.preloaders.DownloadProgressBar;
+
+	public final class CustomPreloader
+		extends DownloadProgressBar
+	{
+		public  var loader : LoadScreen;
+		private var _timer : Timer;
+    
+        public function CustomPreloader() 
+        {
+            super(); 
+        }
+    	
+    	override public function initialize() : void
+    	{
+    		super.initialize();
+    		
+    		this.loader = new LoadScreen();
+    		this.addChild(this.loader);
+    		
+    		this._timer = new Timer(1);
+    		this._timer.addEventListener(TimerEvent.TIMER, handleTimerTick);
+    		this._timer.start();
+    	}
+    	
+        override public function set preloader(preloader : Sprite):void 
+        {                   
+            preloader.addEventListener(ProgressEvent.PROGRESS,  SWFDownLoadScreen);
+            preloader.addEventListener(Event.COMPLETE,          SWFDownloadComplete);
+            preloader.addEventListener(FlexEvent.INIT_PROGRESS, FlexInitProgress);
+            preloader.addEventListener(FlexEvent.INIT_COMPLETE, FlexInitComplete);
+        }
+    
+        private function SWFDownLoadScreen(event : ProgressEvent) : void
+        {
+        	var prog : Number = event.bytesLoaded / event.bytesTotal * 100;
+        	if (this.loader)
+        	{
+        		this.loader.progress = prog;
+        	}
+        }
+        
+        private function handleTimerTick(event : TimerEvent) : void
+        {
+        	this.stage.addChild(this);
+        	this.loader.x = (this.stageWidth  - this.loader.width)  / 2;
+        	this.loader.y = (this.stageHeight - this.loader.height) / 2;
+        	this.loader.refresh();
+        }
+    
+        private function SWFDownloadComplete(event : Event) : void {}
+    
+        private function FlexInitProgress(event : Event) : void {}
+    
+        private function FlexInitComplete(event : Event) : void 
+        {      
+            this.loader.ready = true;
+            this._timer.stop();
+            this.dispatchEvent(new Event(Event.COMPLETE));
+        }
+        
+        override protected function showDisplayForInit(elapsedTime:int, count:int):Boolean
+		{
+			return true;
+		}
+		
+		override protected function showDisplayForDownloading(elapsedTime:int,
+												  event:ProgressEvent):Boolean
+		{
+			return true;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/preloader/LoadScreen.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/preloader/LoadScreen.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/preloader/LoadScreen.as	(revision 15)
@@ -0,0 +1,104 @@
+package gssim.gssimstudio.editor.script.preloader
+{
+	import flash.display.Bitmap;
+	import flash.display.BitmapData;
+	import flash.display.Graphics;
+	import flash.display.Loader;
+	import flash.display.Sprite;
+	import flash.events.Event;
+	import flash.utils.ByteArray;
+	
+	import mx.graphics.codec.PNGEncoder;
+	
+	public class LoadScreen
+		extends Loader
+	{
+        //~ Settings ----------------------------------------------------------
+        private static var _BarWidth     : int = 200;  // Progress bar width
+        private static var _BarHeight    : int = 12;   // Progress bar height
+        private static var _LogoHeight   : int = 35;   // Logo picture height
+        private static var _LogoWidth    : int = 96;  // Logo picture width
+        private static var _Padding      : int = 10;   // Spacing between logo and progress bar
+        private static var _LeftMargin   : int = 5;    // Left Margin
+        private static var _RightMargin  : int = 5;    // Right Margin
+        private static var _TopMargin    : int = 1;    // Top Margin
+        private static var _BottomMargin : int = 1;    // Bottom Margin
+        
+        private static var _BarBackground  : uint = 0xFFFFFF; // background of progress bar
+        private static var _BarOuterBorder : uint = 0x737373; // color of outer border
+        private static var _BarColor       : uint = 0x6F9FD5; // color of prog bar
+        private static var _BarInnerColor  : uint = 0xFFFFFF; // inner color of prog bar
+
+		//~ Instance Attributes -----------------------------------------------
+		[Embed(source="../../assets/logo.png")]
+        private var MyLogoClass: Class;
+        private var _logo : Bitmap;
+        private var _logoData : BitmapData;
+        
+        private var isReady  : Boolean = false;
+        public  var progress : Number;
+
+		//~ Constructor -------------------------------------------------------        
+        public function LoadScreen()
+        {
+        	super();
+        	this.progress = 0;
+        	this._logo = new MyLogoClass as Bitmap;
+        }
+        
+        //~ Methods -----------------------------------------------------------
+        public function refresh() : void
+        {
+        	this._logoData = this.draw();
+        	var encoder : PNGEncoder = new PNGEncoder();
+        	var bytes   : ByteArray  = encoder.encode(this._logoData);
+        	this.loadBytes(bytes);
+        }
+        
+        override public function get width() : Number
+        {
+        	return Math.max(_BarWidth, _LogoWidth) + _LeftMargin + _RightMargin;
+        }
+        
+        override public function get height() : Number
+        {
+        	return _LogoHeight + _BarHeight + _Padding + _TopMargin + _BottomMargin;
+        }
+        
+        private function draw() : BitmapData
+        {
+        	// create bitmap data to create the data
+        	var data : BitmapData = new BitmapData(this.width, this.height, true, 0);
+        
+        	// draw the progress bar
+        	var s : Sprite = new Sprite();
+        	var g : Graphics = s.graphics;
+        	
+        	// draw the bar background
+        	g.beginFill(_BarBackground);
+        	g.lineStyle(2, _BarOuterBorder, 1, true);
+        	var px : int = (this.width - _BarWidth) / 2;
+        	var py : int = _TopMargin + _LogoHeight + _Padding;
+        	g.drawRoundRect(px, py, _BarWidth, _BarHeight, 2);
+        	var containerWidth : Number = _BarWidth - 4;
+        	var progWidth : Number = containerWidth * this.progress / 100;
+        	g.beginFill(_BarColor);
+        	g.lineStyle(1, _BarInnerColor, 1, true);
+        	g.drawRect(px + 1, py + 1, progWidth, _BarHeight - 3);
+        	data.draw(s);
+        	
+        	// draw the logo
+        	data.draw(this._logo.bitmapData, null, null, null, null, true);
+        	return data;
+        }
+        
+        public function set ready(value : Boolean) : void
+        {
+        	this.isReady = value;
+        	this.visible = !this.isReady;
+        }
+        
+        public function get ready() : Boolean { return this.isReady; }
+        
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/views/ViewsHelper.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/views/ViewsHelper.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/views/ViewsHelper.as	(revision 15)
@@ -0,0 +1,15 @@
+package gssim.gssimstudio.editor.script.views
+{
+	import flexlib.mdi.containers.MDICanvas;
+	
+	/**
+	 * This class is used to get fast and simple access to MDICanvas of particular editor
+	 */
+	public final class ViewsHelper
+	{
+		public static var WorkloadCanvas : MDICanvas;
+		public static var TopologyCanvas : MDICanvas;
+		public static var ExperimentCanvas : MDICanvas;
+		public static var ArchiveCanvas : MDICanvas;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenLinkPropertiesWindowCommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenLinkPropertiesWindowCommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenLinkPropertiesWindowCommand.as	(revision 15)
@@ -0,0 +1,39 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.LinkPropertiesWindow;
+	import gssim.gssimstudio.editor.gssim.topology.NetworkObjectLinker;
+	
+	/**
+	 * Open link properties window in network editor
+	 */
+	public class OpenLinkPropertiesWindowCommand implements ICommand
+	{
+		public var linkParamsWindow : LinkPropertiesWindow;
+		public var myContainer : MDICanvas;
+		
+		public function OpenLinkPropertiesWindowCommand(canvas : MDICanvas, link : NetworkObjectLinker)
+		{
+			linkParamsWindow = new LinkPropertiesWindow();
+			linkParamsWindow.init(link);
+			myContainer = canvas;
+		}
+
+		public function execute():void
+		{
+			if (myContainer.getChildByName(linkParamsWindow.name) == null)
+			{
+				myContainer.windowManager.add(linkParamsWindow);
+			}
+		}
+		
+		public function executeFromListener(event : Event):void
+		{
+			execute();
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenMinimapWindowCommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenMinimapWindowCommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenMinimapWindowCommand.as	(revision 15)
@@ -0,0 +1,77 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.MinimapWindow;
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	
+	/**
+	 * Open minimap window in network editor.
+	 */
+	public class OpenMinimapWindowCommand implements ICommand
+	{		
+		private static var minimap : MinimapWindow = new MinimapWindow();
+		public var myContainer : MDICanvas;
+		
+		public function OpenMinimapWindowCommand(canvas : MDICanvas)
+		{
+			myContainer = canvas;
+		}
+
+		public function execute():void
+		{
+			if (myContainer == null) return;
+			if (!myContainer.hasOwnProperty(minimap.id))
+			{
+				var prevX : Number = minimap.x;
+				var prevY : Number = minimap.y;
+				myContainer.windowManager.add(minimap);
+				minimap.x = prevX;
+				minimap.y = prevY;
+			}
+		}
+		
+		public function executeFromListener(event : Event):void
+		{
+			execute();
+		}
+		
+		/* this should be in another command class */
+		/**
+		 * Update GenderObject position on the minimap
+		 */
+		public function update(object : GenderObject, wasDeleted : Boolean = false) : void
+		{
+			minimap.UpdateObject(object, wasDeleted);
+		}
+		
+		/**
+		 * Remove all items from minimap
+		 */
+		public function clean() : void
+		{
+			minimap.clean();
+		}
+		
+		/**
+		 * Recalculate minimap selection box bounds
+		 */
+		public function scale() : void
+		{
+			minimap.scale();
+		}
+		
+		/**
+		 * Initialize minimap window position
+		 */
+		public function init(target : ObjectCanvas) : void
+		{
+			minimap.init(target);
+			minimap.x = minimap.originalX;
+			minimap.y = minimap.originalY;
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/SaveToPNGCommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/SaveToPNGCommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/SaveToPNGCommand.as	(revision 15)
@@ -0,0 +1,43 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.display.BitmapData;
+	import flash.display.DisplayObject;
+	import flash.display.IBitmapDrawable;
+	import flash.events.Event;
+	import flash.geom.Rectangle;
+	import flash.net.FileReference;
+	import flash.utils.ByteArray;
+	
+	import mx.graphics.codec.PNGEncoder;
+	
+	/**
+	 * Save DisplayObject to PNG encoded file selected by user
+	 */
+	public class SaveToPNGCommand implements ICommand
+	{		
+		public var component : DisplayObject;
+		
+		public function SaveToPNGCommand(component : DisplayObject)
+		{
+			this.component = component;
+		}
+
+		public function execute():void
+		{
+			var bitmapData:BitmapData = new BitmapData 
+				(component.width,component.height); 
+			bitmapData.fillRect(new Rectangle 
+				(0,0,bitmapData.width,bitmapData.height),0x00000000); 
+			bitmapData.draw(component); 
+			var fileRef:FileReference = new FileReference(); 
+			var encoder:PNGEncoder = new PNGEncoder(); 
+			var data:ByteArray = encoder.encode(bitmapData); 
+			fileRef.save(data); 
+		}
+		
+		public function executeFromListener(event : Event):void
+		{
+			execute();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/ICommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/ICommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/ICommand.as	(revision 15)
@@ -0,0 +1,19 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	
+	/**
+	 * Interface for Commands
+	 */
+	public interface ICommand
+	{
+		/**
+		 * Execute command (normal)
+		 */
+		function execute() : void;
+		/**
+		 * Execute command bound to event listener
+		 */
+		function executeFromListener(event : Event) : void;		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/ApplyZoomCommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/ApplyZoomCommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/ApplyZoomCommand.as	(revision 15)
@@ -0,0 +1,51 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	import flash.geom.Matrix;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+	
+	/**
+	 * Apply zoom to the object canvas in network editor
+	 */
+	public class ApplyZoomCommand implements ICommand
+	{
+		
+		private static const MINIMUM_ZOOM_VALUE : Number = 0.4;
+		private static const MAXIMUM_ZOOM_VALUE : Number = 2.0;
+		
+		private var objectCanvas : ObjectCanvas;
+		private var delta : Number;
+		private var stageX : Number;
+		private var stageY : Number;
+		
+		public function ApplyZoomCommand(target : ObjectCanvas, delta : Number, tx : Number, ty : Number)
+		{
+			objectCanvas = target;
+			this.delta = delta;
+			stageX = tx;
+			stageY = ty;
+		}
+
+		public function execute():void
+		{
+			var matrix : Matrix = objectCanvas.surface.transform.matrix;
+			var sign : Number = 1;
+			if (delta > 0) sign = 6/5;
+			if (delta < 0) sign = 5/6;
+			if (matrix.a * sign < MINIMUM_ZOOM_VALUE) return;
+			if (matrix.a * sign > MAXIMUM_ZOOM_VALUE) return;
+			objectCanvas.applyZoom(sign, stageX, stageY);
+			var k : OpenMinimapWindowCommand = new OpenMinimapWindowCommand(null);
+			k.scale();
+			objectCanvas.validatePosition();
+		}
+		
+		public function executeFromListener(event:Event):void
+		{
+			execute();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/DoNothing.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/DoNothing.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/DoNothing.as	(revision 15)
@@ -0,0 +1,23 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	
+	/**
+	 * The name says everything - it does nothing...
+	 */
+	public class DoNothing implements ICommand
+	{
+		public function DoNothing()
+		{
+		}
+
+		public function execute():void
+		{
+		}
+		
+		public function executeFromListener(event:Event):void
+		{
+			execute();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenGeneralChartsWindowCommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenGeneralChartsWindowCommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenGeneralChartsWindowCommand.as	(revision 15)
@@ -0,0 +1,49 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.GeneralChartsWindow;
+	
+	/**
+	 * Open charts menu window in network editor
+	 */
+	public class OpenGeneralChartsWindowCommand implements ICommand
+	{
+		private static var chartsWindow : GeneralChartsWindow = new GeneralChartsWindow();
+		public var myContainer : MDICanvas;
+		
+		public function OpenGeneralChartsWindowCommand(canvas : MDICanvas)
+		{
+			myContainer = canvas;
+		}
+
+		public function execute():void
+		{
+			if (!myContainer.hasOwnProperty(chartsWindow.id))
+			{
+				var prevX : Number = chartsWindow.x;
+				var prevY : Number = chartsWindow.y;
+				myContainer.windowManager.add(chartsWindow);
+				chartsWindow.x = prevX;
+				chartsWindow.y = prevY;
+			}
+		}
+		
+		public function executeFromListener(event : Event):void
+		{
+			execute();
+		}
+		
+		/**
+		 * Initialize windows position
+		 */
+		public function init() : void
+		{
+			chartsWindow.x = 100;
+			chartsWindow.y = 100;
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenObjectPropertiesWindowCommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenObjectPropertiesWindowCommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenObjectPropertiesWindowCommand.as	(revision 15)
@@ -0,0 +1,40 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectPropertiesWindow;
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	import gssim.gssimstudio.editor.gssim.editors.topology.paramsWindows.*;
+	
+	/**
+	 * Open gender object properties in edit mode in network editor
+	 */
+	public class OpenObjectPropertiesWindowCommand implements ICommand
+	{
+		public var paramsWindow : ObjectPropertiesWindow;
+		public var myContainer : MDICanvas;
+		
+		public function OpenObjectPropertiesWindowCommand(canvas : MDICanvas, object : GenderObject)
+		{
+			paramsWindow = new ObjectPropertiesWindow();
+			paramsWindow.init(object);
+			myContainer = canvas;
+		}
+
+		public function execute():void
+		{
+			if (myContainer.getChildByName(paramsWindow.name) == null)
+			{
+				myContainer.windowManager.add(paramsWindow);
+			}
+		}
+		
+		public function executeFromListener(event : Event):void
+		{
+			execute();
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenObjectChartListWindowCommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenObjectChartListWindowCommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenObjectChartListWindowCommand.as	(revision 15)
@@ -0,0 +1,60 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+	import gssim.gssimstudio.editor.gssim.topology.ResourceObject;
+	import gssim.gssimstudio.editor.gssim.topology.RouterObject;
+	import gssim.gssimstudio.editor.gssim.topology.UserObject;
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectParamsWindow;
+	import gssim.gssimstudio.editor.gssim.editors.topology.paramsWindows.*;
+	import mx.logging.errors.InvalidCategoryError;
+	
+	/**
+	 * Open chart menu window for network editor.
+	 */
+	public class OpenObjectChartListWindowCommand implements ICommand
+	{
+		public var paramsWindow : ObjectParamsWindow;
+		public var myContainer : MDICanvas;
+		
+		public function OpenObjectChartListWindowCommand(canvas : MDICanvas, object : GenderObject)
+		{
+			if (object is RouterObject)
+			{
+				paramsWindow = new RouterParamsWindow();
+			}
+			else if (object is ResourceObject)
+			{
+				paramsWindow = new ResourceParamsWindow();	
+			}
+			else if (object is UserObject)
+			{
+				paramsWindow = new UserParamsWindow();
+			}
+			else
+			{
+				throw new InvalidCategoryError("Wrong GenderObject type");
+			}
+			
+			paramsWindow.init(object);
+			myContainer = canvas;
+		}
+
+		public function execute():void
+		{
+			if (myContainer.getChildByName(paramsWindow.name) == null)
+			{
+				myContainer.windowManager.add(paramsWindow);
+			}
+		}
+		
+		public function executeFromListener(event : Event):void
+		{
+			execute();
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenToolboxWindowCommand.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenToolboxWindowCommand.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/command/OpenToolboxWindowCommand.as	(revision 15)
@@ -0,0 +1,51 @@
+package gssim.gssimstudio.editor.script.command
+{
+	import flash.events.Event;
+	
+	import flexlib.mdi.containers.MDICanvas;
+	
+	import gssim.gssimstudio.editor.gssim.editors.topology.NetworkEditorToolbox;
+	import gssim.gssimstudio.editor.gssim.editors.topology.ObjectCanvas;
+	
+	/**
+	 * Open toolbox window in network editor
+	 */
+	public class OpenToolboxWindowCommand implements ICommand
+	{
+		private static var toolboxWindow : NetworkEditorToolbox = new NetworkEditorToolbox();
+		public var myContainer : MDICanvas;
+		
+		public function OpenToolboxWindowCommand(canvas : MDICanvas)
+		{
+			myContainer = canvas;
+		}
+
+		public function execute():void
+		{
+			if (!myContainer.hasOwnProperty(toolboxWindow.id))
+			{
+				var prevX : Number = toolboxWindow.x;
+				var prevY : Number = toolboxWindow.y;
+				myContainer.windowManager.add(toolboxWindow);
+				toolboxWindow.x = prevX;
+				toolboxWindow.y = prevY;
+			}
+		}
+		
+		public function executeFromListener(event : Event):void
+		{
+			execute();
+		}
+		
+		/**
+		 * Initialize position of the window
+		 */
+		public function init(target : ObjectCanvas) : void
+		{
+			toolboxWindow.canvas = target;
+			toolboxWindow.x = toolboxWindow.originalX;
+			toolboxWindow.y = toolboxWindow.originalY;
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/utils/ConjunctionArray.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/utils/ConjunctionArray.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/utils/ConjunctionArray.as	(revision 15)
@@ -0,0 +1,34 @@
+package gssim.gssimstudio.editor.script.utils
+{
+	import mx.collections.ArrayCollection;
+
+	public class ConjunctionArray
+	{
+		public var data : ArrayCollection;
+		
+		public function ConjunctionArray()
+		{
+			data = new ArrayCollection();
+		}
+		
+		public function addItem(collection : Array) : void
+		{
+			var temp : ArrayCollection = new ArrayCollection();
+			if (data.length == 0) temp = new ArrayCollection(collection);
+			else
+			{
+				temp.addItem("-1");
+				for each (var item : Object in collection)
+				{
+					if (data.contains(item)) temp.addItem(item);	
+				}
+			}
+			data = temp;
+		}
+		
+		public function clear() : void
+		{
+			data.removeAll();
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/utils/DateTimeUtil.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/utils/DateTimeUtil.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/utils/DateTimeUtil.as	(revision 15)
@@ -0,0 +1,49 @@
+package gssim.gssimstudio.editor.script.utils
+{
+	import mx.formatters.NumberFormatter;
+	
+	/**
+	 * Allows conversion of date string into xsd:DateTime format and vice-versa
+	 */
+	public final class DateTimeUtil
+	{
+		/**
+		 * Convert Date object into xsd:String object
+		 */
+		public static function convertFromDateToString(date : Date) : String
+		{
+			//CCYY-MM-DDThh:mm:ss
+			var result : String = "";
+			result += date.getFullYear().toString() + "-";
+			result += displayTwoDigits(date.getMonth()+1) + "-";
+			result += displayTwoDigits(date.getDate()) + "T";
+			result += displayTwoDigits(date.getHours()) + ":";
+			result += displayTwoDigits(date.getMinutes()) + ":";
+			result += displayTwoDigits(date.getSeconds());
+			return result;
+		}
+		
+		/**
+		 * Convert xsd:DateTime string into Date object
+		 */
+		public static function convertFromStringToDate(string : String) : Date
+		{
+			var date : Date = new Date();
+			var dateStr : String = string.split("T")[0];
+			var timeStr : String = string.split("T")[1];
+			date.setFullYear(dateStr.split("-")[0], Number(dateStr.split("-")[1]) - 1, dateStr.split("-")[2]);
+			date.setHours(timeStr.split(":")[0], timeStr.split(":")[1], timeStr.split(":")[2], 0);
+			return date;
+		}
+
+		/**
+		 * Write two digits even if the number is less than 10
+		 */
+		private static function displayTwoDigits(number : Number) : String
+		{
+			if (number < 10) return "0"+number.toString();
+			return number.toString();
+		}
+
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/ObjectEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/ObjectEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/ObjectEvent.as	(revision 15)
@@ -0,0 +1,29 @@
+package gssim.gssimstudio.editor.script.event
+{
+	import flash.events.Event;
+	
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+
+	/**
+	 * Event bound with GenderObject actions
+	 */
+	public class ObjectEvent extends Event
+	{
+		public var _object : GenderObject;
+		public function get object() : GenderObject
+		{
+			return _object;
+		}
+		
+		public function ObjectEvent(type:String, object : GenderObject, bubbles:Boolean=false, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+			_object = object;
+		}
+
+		override public function clone():Event
+		{
+			return new ObjectEvent(type, object, bubbles, cancelable);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/TextMessageEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/TextMessageEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/TextMessageEvent.as	(revision 15)
@@ -0,0 +1,30 @@
+package gssim.gssimstudio.editor.script.event
+{
+	import flash.events.Event;
+	
+	import gssim.gssimstudio.editor.gssim.topology.GenderObject;
+
+	/**
+	 * Event bound with TextInputWindow actions
+	 */
+	public class TextMessageEvent extends Event
+	{
+		private var _text : String;
+		public function get text() : String
+		{
+			return _text;
+		}
+		
+		public function TextMessageEvent(type:String, text : String, bubbles:Boolean=false, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+			_text=  text;
+		}
+		
+		override public function clone():Event
+		{
+			return new TextMessageEvent(type, text, bubbles, cancelable);
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/LinkEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/LinkEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/LinkEvent.as	(revision 15)
@@ -0,0 +1,29 @@
+package gssim.gssimstudio.editor.script.event
+{
+	import flash.events.Event;
+	
+	import gssim.gssimstudio.editor.gssim.topology.NetworkObjectLinker;
+
+	/**
+	 * Event bound with Link actions
+	 */
+	public class LinkEvent extends Event
+	{
+		private var _link : NetworkObjectLinker;
+		public function get link() : NetworkObjectLinker
+		{
+			return _link;
+		}
+		
+		public function LinkEvent(type:String, link : NetworkObjectLinker, bubbles:Boolean=false, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+			_link = link;
+		}
+		
+		override public function clone():Event
+		{
+			return new LinkEvent(type, link, bubbles, cancelable);
+		}
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/InvalidActionEvent.as
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/InvalidActionEvent.as	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/app/gssim/gssimstudio/editor/script/event/InvalidActionEvent.as	(revision 15)
@@ -0,0 +1,30 @@
+package gssim.gssimstudio.editor.script.event
+{
+	import flash.events.Event;
+	
+	import gssim.gssimstudio.editor.gssim.topology.NetworkObjectLinker;
+
+	/**
+	 * Event bound with invalid user action
+	 */
+	public class InvalidActionEvent extends Event
+	{
+		private var _message : String;
+		public function get message() : String
+		{
+			return _message;
+		}
+		
+		public function InvalidActionEvent(type:String, message : String, bubbles:Boolean=false, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+			_message = message;
+		}
+		
+		override public function clone():Event
+		{
+			return new InvalidActionEvent(type, message, bubbles, cancelable);
+		}
+		
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ResourceChart.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ResourceChart.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ResourceChart.java	(revision 15)
@@ -0,0 +1,368 @@
+package gssim.gssimstudio.flex.app.editor;
+
+import java.io.*;
+import java.util.*;
+
+import org.vinetoolkit.ResourceManager;
+import org.vinetoolkit.ServiceContext;
+import org.vinetoolkit.Session;
+
+import org.vinetoolkit.web.spi.annotation.BlazeDsDestination;
+import org.vinetoolkit.web.spi.annotation.BlazeDsMethod;
+import org.vinetoolkit.web.flex.blazeds.shared.utils.VineFlexUtilClass;
+import org.vinetoolkit.web.portlet.spi.annotation.PortletDisplayName;
+import org.vinetoolkit.role.VineRoleManager;
+import org.vinetoolkit.spi.util.ServiceLog;
+
+import flex.messaging.FlexContext;
+import org.vinetoolkit.web.spi.annotation.BlazeDsDestination;
+import org.vinetoolkit.web.spi.annotation.BlazeDsMethod;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.disk.DiskFileItem;
+import org.vinetoolkit.io.*;
+import org.vinetoolkit.io.sets.FileLocationSet;
+import org.vinetoolkit.ServiceContext;
+import org.vinetoolkit.Location;
+import org.vinetoolkit.task.TaskMonitor;
+import org.vinetoolkit.task.TaskOptions;
+import org.vinetoolkit.task.TaskException;
+import org.vinetoolkit.localhost.io.FileSystemResource;
+import org.vinetoolkit.localhost.io.FileSystemManager;
+import org.vinetoolkit.spi.util.ServiceLog;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+
+import org.vinetoolkit.web.flex.blazeds.shared.uibackend.ModelInitialization;
+import org.vinetoolkit.web.flex.blazeds.shared.uibackend.FileUploadAccepter;
+import java.security.Principal;
+
+import gssim.db.dao.data.Allocation;
+import gssim.db.dao.data.AllocationDetails;
+import gssim.db.dao.data.BlobProperty;
+import gssim.db.dao.data.Configuration;
+import gssim.db.dao.data.Metaexperiment;
+import gssim.db.dao.data.Experiment;
+import gssim.db.dao.data.ExperimentStats;
+import gssim.db.dao.data.Queues;
+import gssim.db.dao.data.Plugin;
+import gssim.db.dao.data.PluginCompatibility;
+import gssim.db.dao.data.Reservation;
+import gssim.db.dao.data.ReservationDetails;
+import gssim.db.dao.data.Resource;
+import gssim.db.dao.data.ResourceAllTimeline;
+import gssim.db.dao.data.ResourceEnTimeline;
+import gssim.db.dao.data.Task;
+import gssim.db.dao.data.TextProperty;
+import gssim.db.dao.data.Unit;
+import gssim.db.dao.data.UnitAllTimeline;
+import gssim.db.dao.data.UnitDetails;
+import gssim.db.dao.data.UnitEnTimeline;
+import gssim.db.dao.data.User;
+import gssim.db.find.Finder;
+import gssim.db.mysql.AllocationDAO;
+import gssim.db.mysql.AllocationDetailsDAO;
+import gssim.db.mysql.BlobPropertyDAO;
+import gssim.db.mysql.ConfigurationDAO;
+import gssim.db.mysql.ExperimentDAO;
+import gssim.db.mysql.MetaexperimentDAO;
+import gssim.db.mysql.ExperimentStatsDAO;
+import gssim.db.mysql.MySQLDAOFactory;
+import gssim.db.mysql.QueuesDAO;
+import gssim.db.mysql.PluginDAO;
+import gssim.db.mysql.PluginCompatibilityDAO;
+import gssim.db.mysql.ReservationDAO;
+import gssim.db.mysql.ReservationDetailsDAO;
+import gssim.db.mysql.ResourceAllTimelineDAO;
+import gssim.db.mysql.ResourceDAO;
+import gssim.db.mysql.ResourceEnTimelineDAO;
+import gssim.db.mysql.TaskDAO;
+import gssim.db.mysql.TextPropertyDAO;
+import gssim.db.mysql.UnitAllTimelineDAO;
+import gssim.db.mysql.UnitDAO;
+import gssim.db.mysql.UnitDetailsDAO;
+import gssim.db.mysql.UnitEnTimelineDAO;
+import gssim.db.mysql.UserDAO;
+
+import java.net.MalformedURLException;
+
+import javax.servlet.ServletContext;
+
+/**
+ * @author Mateusz Cichenski, Jarek Szymczak
+ */
+@BlazeDsDestination(portletEntry = false, locales = {"en_US","pl_PL"}, names = {"GSSim Studio","GSSim Studio"}, descriptions = {"Application for GSSim job description","Aplikacja do generowania zadaï¿œ dla symulatora GSSim"})
+public class ResourceChart {
+
+	/**
+	 * The location of database source
+	 */
+	private String dbAddress = "seagrass.man.poznan.pl:3306/gssim_results";
+	/**
+	 * Username to access database
+	 */
+	private String dbUser = "gssim";
+	/**
+	 * Password to database [is it safe?]
+	 */
+	private String dbPassword = "Ua7Ahs9r";
+	
+	private Boolean developement = true;
+
+	private static MySQLDAOFactory factory;
+
+	/**
+	 * Logger instance for this class
+	 */
+    private ServiceLog log = ServiceLog.getInstance(ResourceChart.class);
+
+    @BlazeDsMethod()
+	public ResourceChartModel setSelectedResourceIndex(Integer index) {
+
+		ResourceChartModel model = (ResourceChartModel) VineFlexUtilClass.getUIModel();
+		model.setSelectedResourceIndex(index);
+		return model;
+	}
+    
+    @BlazeDsMethod()
+	public ResourceChartModel getExperimentConfiguration(Integer expId) {
+
+		ResourceChartModel model = (ResourceChartModel) VineFlexUtilClass.getUIModel();
+		
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExperimentDAO experimentDAO = factory.createExperiment();
+			Experiment exp = new Experiment();
+			exp.setPK(expId);
+			exp = experimentDAO.select(exp);
+			
+			TextPropertyDAO propertyDAO = factory.createTextProperty();
+			Finder finder = Finder.getTextPropertyFinder(exp.getConfigId());
+
+			List<TextProperty> list = propertyDAO.find(finder);
+			HashMap<String, String> map = new HashMap<String, String>();
+			for (int i = 0; i < list.size(); i++)
+			{
+				map.put(list.get(i).getName(), list.get(i).getValue());
+			}
+
+			model.setExperimentConfiguration(map);
+
+		} catch (SQLException e) {
+			setSqlError("Resources", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+    
+	@BlazeDsMethod()
+	public ResourceChartModel getResourcesFromDb(Integer expId, String name,
+			String type) {
+
+		ResourceChartModel model = (ResourceChartModel) VineFlexUtilClass.getUIModel();
+		
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			ResourceDAO resourceDAO = factory.createResource();
+			Finder finder = Finder.getResourceFinder(expId, name, type);
+
+			List<Resource> list = resourceDAO.find(finder);
+			Resource blank = new Resource();
+			blank.setPK(-1);
+			blank.setName("(...)");
+			list.add(0, blank);
+
+			model.setResourceList(list);
+
+		} catch (SQLException e) {
+			setSqlError("Resources", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	@BlazeDsMethod()
+	public ResourceChartModel getResourceAllTimelineFromDb(Integer resourceId, Integer expId,
+			Long minTimestampMilis, Long maxTimestampMilis) {
+
+		ResourceChartModel model = (ResourceChartModel) VineFlexUtilClass.getUIModel();
+		
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			ResourceAllTimelineDAO resourceDAO = factory
+					.createResourceAllTimeline();
+
+			Timestamp minTimestamp = minTimestampMilis == null ? null
+					: new Timestamp(minTimestampMilis);
+			Timestamp maxTimestamp = maxTimestampMilis == null ? null
+					: new Timestamp(maxTimestampMilis);
+
+			if (resourceId != -1)
+			{
+				Finder finder = Finder.getResourceAllocationTimelineFinder(resourceId, minTimestamp, maxTimestamp);
+				List<ResourceAllTimeline> list = resourceDAO.find(finder);
+
+				model.setResourceTimelineList(list);
+
+			}
+			else
+			{
+				Finder finder = Finder.getResourceAllocationTimelineFinder(
+						expId, minTimestamp, maxTimestamp);
+				List<ResourceAllTimeline> list = resourceDAO.sum(finder);
+
+				model.setResourceTimelineList(list);
+
+			}
+
+		} catch (SQLException e) {
+			setSqlError("Resources allocation timeline", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public ResourceChartModel getResourceEnTimelineFromDb(Integer resourceId, Integer expId,
+			Long minTimestampMilis, Long maxTimestampMilis) {
+
+		ResourceChartModel model = (ResourceChartModel) VineFlexUtilClass.getUIModel();
+
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			ResourceEnTimelineDAO resourceDAO = factory
+					.createResourceEnTimeline();
+
+			Timestamp minTimestamp = minTimestampMilis == null ? null
+					: new Timestamp(minTimestampMilis);
+			Timestamp maxTimestamp = maxTimestampMilis == null ? null
+					: new Timestamp(maxTimestampMilis);
+
+			if (resourceId != -1)
+			{
+				Finder finder = Finder.getResourceAllocationTimelineFinder(resourceId, minTimestamp, maxTimestamp);
+				List<ResourceEnTimeline> list = resourceDAO.find(finder);
+
+				model.setResourceTimelineList(list);
+
+			}
+			else
+			{
+				Finder finder = Finder.getResourceAllocationTimelineFinder(
+						expId, minTimestamp, maxTimestamp);
+				List<ResourceEnTimeline> list = resourceDAO.sum(finder);
+
+				model.setResourceTimelineList(list);
+
+			}
+
+		} catch (SQLException e) {
+			setSqlError("Resources energy timeline", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	private void closeConnection(Connection connection, ResourceChartModel model) {
+		String error = model.getError();
+		
+		if (connection != null)
+			try {
+				connection.close();
+			} catch (SQLException e) {
+				error = model.getError();
+				if (error == null || error.equals("")) {
+					error = "Error while trying to close the SQL connection";
+				} else {
+					error += System.getProperty("line.separator");
+					error += "Error while trying to close the SQL connection";
+				}
+			}
+
+		model.setError(error);
+	}
+
+	private void setSqlError(String name, ResourceChartModel model, Exception e) {
+		setError(name + ": an SQL exception occured while trying retrieve data from database", model, e);
+	}
+	
+	private void setDbConnectionError(ResourceChartModel model, Exception e) {
+		setError("An exception occured while trying to create MySQLDAOFactory", model, e);
+	}
+	
+	private void setError(String messageForUser, ResourceChartModel model, Exception e) {
+		
+		String error = messageForUser;
+		
+		if(developement)
+		{
+			error += System.getProperty("line.separator");
+			error += "Error details:";
+			error += System.getProperty("line.separator");
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			PrintStream ps = new PrintStream(baos);
+			e.printStackTrace(ps);
+			String stackTrace = baos.toString();		
+			error += stackTrace;
+		}
+		
+		model.setError(error);
+	}			
+	
+	private MySQLDAOFactory factory() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+		if(factory == null)
+			factory = new MySQLDAOFactory();
+		return factory;
+	}
+	/* END OF DB Methods */
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudio.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudio.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudio.java	(revision 15)
@@ -0,0 +1,2145 @@
+package gssim.gssimstudio.flex.app.editor;
+
+import java.io.*;
+import java.util.*;
+
+import org.vinetoolkit.ResourceManager;
+import org.vinetoolkit.ServiceContext;
+import org.vinetoolkit.Session;
+
+import org.vinetoolkit.web.spi.annotation.BlazeDsDestination;
+import org.vinetoolkit.web.spi.annotation.BlazeDsMethod;
+import org.vinetoolkit.web.flex.blazeds.shared.utils.VineFlexUtilClass;
+import org.vinetoolkit.web.portlet.spi.annotation.PortletDisplayName;
+import org.vinetoolkit.role.VineRoleManager;
+import org.vinetoolkit.spi.util.ServiceLog;
+
+import org.vinetoolkit.grms3client.GRMS3ClientModule;
+import org.vinetoolkit.grms3client.GRMS3ClientResource;
+import org.vinetoolkit.grms3client.GRMS3Job;
+import org.vinetoolkit.grms3client.GRMS3Resource;
+import org.vinetoolkit.grms3client.GRMS3ReturnType;
+import org.vinetoolkit.grms3client.GRMS3Task;
+import org.vinetoolkit.grms3client.web.app.GRMS3JobImpl;
+import org.vinetoolkit.grms3client.web.app.GRMS3ResourceImpl;
+//import org.vinetoolkit.grms3client.web.app.GRMS3Status;
+
+import flex.messaging.FlexContext;
+import org.vinetoolkit.web.spi.annotation.BlazeDsDestination;
+import org.vinetoolkit.web.spi.annotation.BlazeDsMethod;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.disk.DiskFileItem;
+import org.vinetoolkit.io.*;
+import org.vinetoolkit.io.sets.FileLocationSet;
+import org.vinetoolkit.ServiceContext;
+import org.vinetoolkit.Location;
+import org.vinetoolkit.task.TaskMonitor;
+import org.vinetoolkit.task.TaskOptions;
+import org.vinetoolkit.task.TaskException;
+import org.vinetoolkit.localhost.io.FileSystemResource;
+import org.vinetoolkit.localhost.io.FileSystemManager;
+import org.vinetoolkit.spi.util.ServiceLog;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+
+import org.vinetoolkit.web.flex.blazeds.shared.uibackend.ModelInitialization;
+import org.vinetoolkit.web.flex.blazeds.shared.uibackend.FileUploadAccepter;
+import java.security.Principal;
+
+import gssim.db.dao.data.Allocation;
+import gssim.db.dao.data.AllocationDetails;
+import gssim.db.dao.data.BlobProperty;
+import gssim.db.dao.data.Configuration;
+import gssim.db.dao.data.Metaexperiment;
+import gssim.db.dao.data.Experiment;
+import gssim.db.dao.data.ExperimentStats;
+import gssim.db.dao.data.Queues;
+import gssim.db.dao.data.Plugin;
+import gssim.db.dao.data.PluginCompatibility;
+import gssim.db.dao.data.Reservation;
+import gssim.db.dao.data.ReservationDetails;
+import gssim.db.dao.data.Resource;
+import gssim.db.dao.data.ResourceAllTimeline;
+import gssim.db.dao.data.ResourceEnTimeline;
+import gssim.db.dao.data.Task;
+import gssim.db.dao.data.TextProperty;
+import gssim.db.dao.data.Unit;
+import gssim.db.dao.data.UnitAllTimeline;
+import gssim.db.dao.data.UnitDetails;
+import gssim.db.dao.data.UnitEnTimeline;
+import gssim.db.dao.data.User;
+import gssim.db.find.Finder;
+import gssim.db.mysql.AllocationDAO;
+import gssim.db.mysql.AllocationDetailsDAO;
+import gssim.db.mysql.BlobPropertyDAO;
+import gssim.db.mysql.ConfigurationDAO;
+import gssim.db.mysql.ExperimentDAO;
+import gssim.db.mysql.MetaexperimentDAO;
+import gssim.db.mysql.ExperimentStatsDAO;
+import gssim.db.mysql.MySQLDAOFactory;
+import gssim.db.mysql.QueuesDAO;
+import gssim.db.mysql.PluginDAO;
+import gssim.db.mysql.PluginCompatibilityDAO;
+import gssim.db.mysql.ReservationDAO;
+import gssim.db.mysql.ReservationDetailsDAO;
+import gssim.db.mysql.ResourceAllTimelineDAO;
+import gssim.db.mysql.ResourceDAO;
+import gssim.db.mysql.ResourceEnTimelineDAO;
+import gssim.db.mysql.TaskDAO;
+import gssim.db.mysql.TextPropertyDAO;
+import gssim.db.mysql.UnitAllTimelineDAO;
+import gssim.db.mysql.UnitDAO;
+import gssim.db.mysql.UnitDetailsDAO;
+import gssim.db.mysql.UnitEnTimelineDAO;
+import gssim.db.mysql.UserDAO;
+
+import java.net.MalformedURLException;
+
+import javax.servlet.ServletContext;
+
+/**
+ * @author Mateusz Cichenski, Jarek Szymczak
+ */
+@BlazeDsDestination(swfHeight = "800", locales = {"en_US","pl_PL"}, names = {"GSSim Studio","GSSim Studio"}, descriptions = {"Application for GSSim job description","Aplikacja do generowania zadaï¿œ dla symulatora GSSim"})
+@PortletDisplayName(locales = {"en", "pl"}, values = {"GSSimStudio Application", "Aplikacja GSSimStudio"})
+public class GSSimStudio implements ModelInitialization , FileUploadAccepter {
+
+	/**
+	 * The location of database source
+	 */
+	private String dbAddress = "seagrass.man.poznan.pl:3306/gssim_results";
+	/**
+	 * Username to access database
+	 */
+	private String dbUser = "gssim";
+	/**
+	 * Password to database [is it safe?]
+	 */
+	private String dbPassword = "Ua7Ahs9r";
+	
+	private Boolean developement = true;
+
+	private static MySQLDAOFactory factory;
+
+	//FIXME: usunac to potem
+	protected final static String resourceBoundle = "locale.grms3client";
+	
+	/**
+	 * Logger instance for this class
+	 */
+    private ServiceLog log = ServiceLog.getInstance(GSSimStudio.class);
+    
+    @BlazeDsMethod()
+	public GSSimStudioModel uploadAndSubmitExperiment(String destFileName, String fileContent, String grmsURL, String grmsDN, String jobDescription) throws IOException {
+		String expName = destFileName.split("_")[1].split(".properties")[0];
+		String metaexpName = destFileName.split("_")[0];
+		Integer expId = addExperimentToDb(expName, metaexpName);
+		fileContent += "experiment.id="+expId.toString();
+		uploadPropertyFile(destFileName, fileContent);
+		
+		return doSubmitApplication(grmsURL, grmsDN, jobDescription);
+	}
+    
+	/* DB Methods */
+	protected void getPluginsFromDb(GSSimStudioModel model) {
+		Connection connection = null;
+		
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			PluginDAO pluginDAO = factory.createPlugin();
+			Finder finder = Finder.getPluginFinder(null, null, null);
+			List<Plugin> list = pluginDAO.find(finder);
+			
+			PluginCompatibilityDAO compatibilityDAO = factory.createPluginCompatibility();
+			Finder finderC = Finder.getPluginCompatibilityFinder(null, null);
+			List<PluginCompatibility> listC = compatibilityDAO.find(finderC);
+			HashMap<Integer, String> compatiblePlugins = new HashMap<Integer, String>();
+			String allPluginIds = "-1";
+			for (int i = 0; i < list.size(); i++)
+			{
+				//insert compatibility to "none" plugin
+				compatiblePlugins.put(list.get(i).getPK(), "-1");
+				allPluginIds += ","+list.get(i).getPK();
+			}
+			for (int i = 0; i < listC.size(); i++)
+			{
+				Integer parent = listC.get(i).getParentId();
+				Integer child = listC.get(i).getChildId();
+				String tmp = compatiblePlugins.get(parent);
+				tmp += "," + child.toString();
+				compatiblePlugins.put(parent, tmp);
+				tmp = compatiblePlugins.get(child);
+				tmp += "," + parent.toString();
+				compatiblePlugins.put(child, tmp);
+			}
+			
+			List<HashMap<String, String>> local = new ArrayList<HashMap<String, String>>();
+			model.setLocalPluginList(local);
+			List<HashMap<String, String>> global = new ArrayList<HashMap<String, String>>();
+			model.setGlobalPluginList(global);
+			
+			HashMap<String, String> noneMap = new HashMap<String, String>();
+			noneMap.put("label", "(...)");
+			noneMap.put("id", "-1");
+			noneMap.put("compatible", allPluginIds);
+			global.add(noneMap);
+			local.add(noneMap);
+			
+			for (int i = 0; i < list.size(); i++)
+			{
+				Plugin plugin = list.get(i);
+				HashMap<String, String> pluginMap = new HashMap<String, String>();
+				pluginMap.put("label", plugin.getName());
+				pluginMap.put("data", plugin.getInput());
+				pluginMap.put("description", plugin.getDescription());
+				pluginMap.put("id", plugin.getPK().toString());
+				pluginMap.put("compatible", compatiblePlugins.get(plugin.getPK()));
+				if (plugin.getIsGlobal()) global.add(pluginMap);
+				else local.add(pluginMap);
+			}
+			
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Allocations", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+	}
+    
+	@BlazeDsMethod()
+	public GSSimStudioModel getAllocationsFromDb(Integer taskId, Integer unitId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			AllocationDAO allocationDAO = factory.createAllocation();
+			Finder finder = Finder.getAllocationFinder(taskId, unitId);
+
+			List<Allocation> list = allocationDAO.find(finder);
+
+			model.setAllocationList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Allocations", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getAllocationDetailsFromDb(Integer allocationId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			AllocationDetailsDAO allocationDetailsDAO = factory
+					.createAllocationDetails();
+			Finder finder = Finder.getAllocationDetailsFinder(allocationId);
+
+			List<AllocationDetails> list = allocationDetailsDAO.find(finder);
+
+			model.setAllocationDetailsList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Allocation details", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getBlobPropertiesFromDb(Integer configId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			BlobPropertyDAO blobPropertyDAO = factory.createBlobProperty();
+			Finder finder = Finder.getBlobPropertyFinder(configId);
+
+			List<BlobProperty> list = blobPropertyDAO.find(finder);
+
+			model.setBlobPropertyList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Blob properties", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	protected int addExperimentToDb(String expName, String metaexperiment) {
+		Connection connection = null;
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExperimentDAO experimentDAO = factory.createExperiment();
+			UserDAO userDAO = factory.createUser();
+			ConfigurationDAO configurationDAO = factory.createConfiguration();
+			MetaexperimentDAO metaDAO = factory.createMetaexperiment();
+			
+			Experiment experiment = new Experiment();
+			
+			Configuration configuration = new Configuration();
+			configurationDAO.insert(configuration, false);
+
+			User user = new User();
+			user.setDN("unknown_user");
+			userDAO.insert(user, false);
+			
+			int metaId = getMetaexpId(metaDAO, metaexperiment);
+			if (metaId == -1) metaId = addMetaexperiment(metaDAO, metaexperiment);
+			
+			experiment.setMetaexpId(metaId);
+			experiment.setName(expName);
+			experiment.setStatus("SUBMITTED");
+			experiment.setConfigId(configuration.getId());
+			experiment.setUserId(user.getId());
+			Timestamp time = new Timestamp((new Date()).getTime());
+			experiment.setCommissionDate(time);
+			experimentDAO.insert(experiment, false);
+			connection.commit();
+			
+			return experiment.getPK();
+			
+		} catch (SQLException e) {
+			setSqlError("Experiments", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return -1;
+	}
+	
+	/**
+	 * Look for metaexperiment with the given name.
+	 * 
+	 */
+	protected int getMetaexpId(MetaexperimentDAO metaDAO, String metaexpname) throws SQLException
+	{
+		List<Metaexperiment> list = metaDAO.find(Finder.getMetaexperimentFinder(metaexpname));
+		if (list.size() == 1) return list.get(0).getId();
+		return -1;
+	}
+	
+	/**
+	 * Add new metaexperiment with the given name.
+	 */
+	protected int addMetaexperiment(MetaexperimentDAO metaDAO, String metaexpname) throws SQLException
+	{
+		Metaexperiment meta = new Metaexperiment();
+		meta.setName(metaexpname);
+		metaDAO.insert(meta, false);
+		return meta.getId();
+	}
+	
+	/**
+	 * Update metaexperiment lists
+	 */
+	protected void getMetaexperimentsFromDb(GSSimStudioModel model, String name) throws SQLException
+	{
+		MetaexperimentDAO metaDAO = factory.createMetaexperiment();
+		Finder finder = Finder.getMetaexperimentFinder(name);
+
+		List<Metaexperiment> list = metaDAO.find(finder);
+		
+		HashMap<Integer, String> map = new HashMap<Integer, String>();
+		model.setMetaexperimentList(map);
+		for (int i = 0; i < list.size(); i++)
+		{
+			map.put(list.get(i).getId(), list.get(i).getName());
+			log.error("Hashmap logged "+i+" = " + list.get(i).getName());
+		}
+		
+		model.setError("");
+	}
+
+	/**
+	 * Delete experiment with the given key.
+	 */
+	protected void deleteExperiment(ExperimentDAO experimentDAO, Integer PK) throws SQLException
+	{
+		Experiment experiment = new Experiment();
+		experiment.setPK(PK);
+		experimentDAO.delete(experiment, false);
+	}
+	
+	/**
+	 * Change experiment with the given key.
+	 * Factory needs to be initialized! [by appropriate connection]
+	 */
+	protected void updateExperiment(ExperimentDAO experimentDAO, Integer PK, Integer userID, Integer configID, String name, Timestamp commissionDate, String description, String status, Integer metaexpID) throws SQLException
+	{
+		Experiment experiment = new Experiment();
+		experiment.setPK(PK);
+		experiment = experimentDAO.select(experiment);
+		if (userID != -1) experiment.setUserId(userID);
+		if (configID != -1) experiment.setConfigId(configID);
+		if (commissionDate != null) experiment.setCommissionDate(commissionDate);
+		if (name != null) experiment.setName(name);
+		if (description != null) experiment.setDescription(description);
+		if (status != null) experiment.setStatus(status);
+		if (metaexpID != -1) experiment.setMetaexpId(metaexpID);
+		experimentDAO.update(experiment, false);
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel deleteExperiment(Integer PK) {
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExperimentDAO experimentDAO = factory.createExperiment();
+			deleteExperiment(experimentDAO, PK);
+			
+			connection.commit();
+			
+		} catch (SQLException e) {
+			setSqlError("Experiments", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+		
+		return getExperimentsFromDb(model, null, null, null);
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel updateExperiment(Integer PK, Integer userID, Integer configID, String name, Timestamp commissionDate, String description, String status, Integer metaexpID) {
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExperimentDAO experimentDAO = factory.createExperiment();
+			
+			updateExperiment(experimentDAO, PK, userID, configID, name, commissionDate, description, status, metaexpID);
+			
+			connection.commit();
+			
+		} catch (SQLException e) {
+			setSqlError("Experiments", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+		
+		return getExperimentsFromDb(model, null, null, null);
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel changeExperimentsMetaexperiment(List experiments, String metaexperiment) {
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExperimentDAO experimentDAO = factory.createExperiment();
+			MetaexperimentDAO metaDAO = factory.createMetaexperiment();
+			
+			int metaId = getMetaexpId(metaDAO, metaexperiment);
+			if (metaId == -1) metaId = addMetaexperiment(metaDAO, metaexperiment);
+			
+			for (int i = 0; i < experiments.size(); i++)
+			{
+				updateExperiment(experimentDAO, (Integer) experiments.get(i), -1, -1, null, null, null, null, metaId);
+			}
+			
+			connection.commit();
+			
+		} catch (SQLException e) {
+			setSqlError("Experiments", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+		
+		return getExperimentsFromDb(model, null, null, null);
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getExperimentNetworkTopology(Integer PK) {
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExperimentDAO experimentDAO = factory.createExperiment();
+			Experiment experiment = new Experiment();
+			experiment.setPK(PK);
+			experiment = experimentDAO.select(experiment);
+			
+			BlobPropertyDAO blobDAO = factory.createBlobProperty();
+			BlobProperty blob = new BlobProperty();
+			blob.setConfigId(experiment.getConfigId());
+			blob.setName(GSSimStudioConstants.NetworkTopologyBlobProperty);
+			blob = blobDAO.select(blob);
+			
+			if (blob != null)
+				model.setCurrentExperimentNetworkTopology(blob.getValue());
+			else
+				model.setCurrentExperimentNetworkTopology(null);
+			
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Experiments", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getExperimentsFromDb(Integer userId,
+			Boolean publish, String status) {
+		return getExperimentsFromDb(null, userId, publish, status);
+	}
+	
+	protected GSSimStudioModel getExperimentsFromDb(GSSimStudioModel model, Integer userId,
+			Boolean publish, String status) {
+
+		if (model == null) model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			getMetaexperimentsFromDb(model, null);
+			
+			ExperimentDAO experimentDAO = factory.createExperiment();
+			Finder finder = Finder.getExperimentFinder(userId, null, null, null, null, status, null);
+
+			List<Experiment> list = experimentDAO.find(finder);
+
+			model.setExperimentList(list);
+			model.setExperimentListChanged(true);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Experiments", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getExperimentStatsFromDb(Integer experimentId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			ExperimentStatsDAO experimentStatsDAO = factory.createExperimentStats();
+			Finder finder = Finder.getExperimentStatsFinder(experimentId);
+			List<ExperimentStats> list = experimentStatsDAO.find(finder);
+
+			model.setExperimentStatsList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Experiment stats", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getExtendedConfigurationFromDb(int id) {
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExtendedConfiguration extendedConfiguration = new ExtendedConfiguration();
+			
+			ConfigurationDAO configurationDAO = factory.createConfiguration();
+
+			Configuration configuration = new Configuration();
+			configuration.setId(id);
+			configuration = configurationDAO.select(configuration);
+			
+			if(configuration != null) {
+
+				TextPropertyDAO textPropertyDAO = factory.createTextProperty();
+				Finder finder = Finder.getTextPropertyFinder(configuration.getId());
+	
+				List<TextProperty> textPropertyList = textPropertyDAO.find(finder);
+				
+				BlobPropertyDAO blobPropertyDAO = factory.createBlobProperty();
+				finder = Finder.getBlobPropertyFinder(configuration.getId());
+
+				List<BlobProperty> blobPropertyList = blobPropertyDAO.find(finder);
+				
+				extendedConfiguration.setConfigurationId(configuration.getId());
+				extendedConfiguration.setTextPropertyList(textPropertyList);
+				extendedConfiguration.setBlobPropertyList(blobPropertyList);
+				
+				BlobProperty networkTopologyBlob = new BlobProperty();
+				networkTopologyBlob.setConfigId(configuration.getId());
+				networkTopologyBlob.setName("Network topology");
+				networkTopologyBlob = blobPropertyDAO.select(networkTopologyBlob);
+				
+				String networkTopology = new String(networkTopologyBlob.getValue(), "utf-8");
+				extendedConfiguration.setNetworkTopology(networkTopology);
+			
+				model.setExtendedConfiguration(extendedConfiguration);
+			}
+			
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Configuration", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+
+	}	
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getQueuesFromDb(Integer resourceId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			QueuesDAO queuesDAO = factory.createQueues();
+			Finder finder = Finder.getQueuesFinder(resourceId);
+
+			List<Queues> list = queuesDAO.find(finder);
+
+			model.setQueuesList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Queueus", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getReservationsFromDb(Integer taskId, Integer unitId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			ReservationDAO ReservationDAO = factory.createReservation();
+			Finder finder = Finder.getReservationFinder(taskId, unitId);
+
+			List<Reservation> list = ReservationDAO.find(finder);
+
+			model.setReservationList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Reservations", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getReservationDetailsFromDb(Integer reservationId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			ReservationDetailsDAO reservationDetailsDAO = factory
+					.createReservationDetails();
+			Finder finder = Finder.getReservationDetailsFinder(reservationId);
+
+			List<ReservationDetails> list = reservationDetailsDAO.find(finder);
+
+			model.setReservationDetailsList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Reservation details", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel setSelectedResourceIndex(int index, Integer res) {
+		return delegate(new Object[]{res}, index);
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getResourcesFromDb(int index, Integer expId, String name,
+			String type) {
+		return delegate(new Object[]{expId, name, type}, index);
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getResourceAllTimelineFromDb(int index, Integer resourceId, Integer expId,
+			Long minTimestampMilis, Long maxTimestampMilis) {
+		return delegate(new Object[]{resourceId, expId, minTimestampMilis, maxTimestampMilis}, index);
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getResourceEnTimelineFromDb(int index, Integer resourceId, Integer expId,
+			Long minTimestampMilis, Long maxTimestampMilis) {
+		return delegate(new Object[]{resourceId, expId, minTimestampMilis, maxTimestampMilis}, index);
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getExperimentConfiguration(int index, Integer expId) {
+		return delegate(new Object[]{expId}, index);
+	}
+	
+	protected GSSimStudioModel delegate(Object[] parameters, Integer index) {
+		GSSimStudioModel gssimStudioModel = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+        ResourceChartModel resourceChartModel = (ResourceChartModel) gssimStudioModel.getResourceChartComponents().get(index.toString());
+        if (resourceChartModel == null)
+        {
+        	resourceChartModel = new ResourceChartModel();
+        	gssimStudioModel.getResourceChartComponents().put(index.toString(), resourceChartModel);
+        }
+        VineFlexUtilClass.invokeDestination(ResourceChart.class, parameters, resourceChartModel);
+        return gssimStudioModel;
+    }
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getComparisonFromDb(int index, List experiments, List parameters) {
+		return delegateComparison(new Object[]{experiments, parameters}, index);
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getCategoryComparisonFromDb(int index, List experiments, List parameters) {
+		return delegateComparison(new Object[]{experiments, parameters}, index);
+	}
+
+	protected GSSimStudioModel delegateComparison(Object[] parameters, Integer index) {
+		GSSimStudioModel gssimStudioModel = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		ExperimentComparisonChartModel experimentComparisonChartModel = (ExperimentComparisonChartModel) gssimStudioModel.getComparisonComponents().get(index.toString());
+        if (experimentComparisonChartModel == null)
+        {
+        	experimentComparisonChartModel = new ExperimentComparisonChartModel();
+        	gssimStudioModel.getComparisonComponents().put(index.toString(), experimentComparisonChartModel);
+        }
+        VineFlexUtilClass.invokeDestination(ExperimentComparisonChart.class, parameters, experimentComparisonChartModel);
+        return gssimStudioModel;
+    }
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getTasksFromDb(Integer type, Integer expId,
+			Integer jobId, Integer taskId, Integer procSetId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+
+			TaskDAO taskDAO = factory.createTask();
+			Finder finder = Finder.getTaskFinder(expId, jobId, taskId,
+					procSetId);
+
+			TaskDAO.Type taskType = null;
+
+			if(type != null)
+			{
+				switch (type) {
+				case 0:
+					taskType = TaskDAO.Type.JOB;
+					break;
+				case 1:
+					taskType = TaskDAO.Type.TASK;
+					break;
+				case 2:
+					taskType = TaskDAO.Type.PROCESS_SET;
+					break;
+				default:
+					taskType = null;
+				}
+			}
+
+			List<Task> list;
+
+			if (taskType == null)
+				list = taskDAO.find(finder);
+			else
+				list = taskDAO.find(finder, taskType);
+
+			model.setTaskList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Tasks", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getTasksFromDb(Integer type, Integer expId, Integer jobId,
+			Integer taskId, Integer procSetId, Long minExecutionStartDateMilis,
+			Long maxExecutionStartDateMilis, Long minExecutionFinishDateMilis,
+			Long maxExecutionFinishDateMilis) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+
+			TaskDAO taskDAO = factory.createTask();
+
+			Timestamp minExecutionStartDate = minExecutionStartDateMilis == null ? null
+					: new Timestamp(minExecutionStartDateMilis);
+			Timestamp maxExecutionStartDate = maxExecutionStartDateMilis == null ? null
+					: new Timestamp(maxExecutionStartDateMilis);
+			Timestamp minExecutionFinishDate = minExecutionFinishDateMilis == null ? null
+					: new Timestamp(minExecutionFinishDateMilis);
+			Timestamp maxExecutionFinishDate = maxExecutionFinishDateMilis == null ? null
+					: new Timestamp(maxExecutionFinishDateMilis);
+
+			Finder finder = Finder.getTaskFinder(expId, jobId, taskId,
+					procSetId, minExecutionStartDate, maxExecutionStartDate,
+					minExecutionFinishDate, maxExecutionFinishDate);
+
+			TaskDAO.Type taskType = null;
+
+			switch (type) {
+			case 0:
+				taskType = TaskDAO.Type.JOB;
+				break;
+			case 1:
+				taskType = TaskDAO.Type.TASK;
+				break;
+			case 2:
+				taskType = TaskDAO.Type.PROCESS_SET;
+				break;
+			default:
+				taskType = null;
+			}
+
+			List<Task> list;
+
+			if (taskType == null)
+				list = taskDAO.find(finder);
+			else
+				list = taskDAO.find(finder, taskType);
+
+			model.setTaskList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Tasks", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getTextPropertiesFromDb(Integer configId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			TextPropertyDAO textPropertyDAO = factory.createTextProperty();
+			Finder finder = Finder.getTextPropertyFinder(configId);
+
+			List<TextProperty> list = textPropertyDAO.find(finder);
+
+			model.setTextPropertyList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Text properties", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getUnitsFromDb(Integer resourceId, String name,
+			String type) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			UnitDAO unitDAO = factory.createUnit();
+			Finder finder = Finder.getUnitFinder(resourceId, name, type);
+
+			List<Unit> list = unitDAO.find(finder);
+
+			model.setUnitList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Units", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getUnitAllTimelineFromDb(Integer unitId,
+			Long minTimestampMilis, Long maxTimestampMilis) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			UnitAllTimelineDAO unitDAO = factory.createUnitAllTimeline();
+
+			Timestamp minTimestamp = minTimestampMilis == null ? null
+					: new Timestamp(minTimestampMilis);
+			Timestamp maxTimestamp = maxTimestampMilis == null ? null
+					: new Timestamp(maxTimestampMilis);
+
+			Finder finder = Finder.getUnitAllocationTimelineFinder(unitId,
+					minTimestamp, maxTimestamp);
+
+			List<UnitAllTimeline> list = unitDAO.find(finder);
+
+			model.setUnitAllTimelineList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Unit allocation timeline", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	@BlazeDsMethod()
+	public GSSimStudioModel getUnitDetailsFromDb(Integer unitId) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			UnitDetailsDAO unitDetailsDAO = factory
+					.createUnitDetails();
+			Finder finder = Finder.getUnitDetailsFinder(unitId);
+
+			List<UnitDetails> list = unitDetailsDAO.find(finder);
+
+			model.setUnitDetailsList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Unit details", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}	
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel getUnitEnTimelineFromDb(Integer unitId,
+			Long minTimestampMilis, Long maxTimestampMilis) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(false);
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			UnitEnTimelineDAO unitDAO = factory.createUnitEnTimeline();
+
+			Timestamp minTimestamp = minTimestampMilis == null ? null
+					: new Timestamp(minTimestampMilis);
+			Timestamp maxTimestamp = maxTimestampMilis == null ? null
+					: new Timestamp(maxTimestampMilis);
+
+			Finder finder = Finder.getUnitAllocationTimelineFinder(unitId,
+					minTimestamp, maxTimestamp);
+
+			List<UnitEnTimeline> list = unitDAO.find(finder);
+
+			model.setUnitEnTimelineList(list);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("Unit energy timeline", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+
+	public GSSimStudioModel getUser(int id) {
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			UserDAO userDAO = factory.createUser();
+
+			User user = new User();
+			user.setId(id);
+			user = userDAO.select(user);
+
+			model.setUser(user);
+			model.setError("");
+
+		} catch (SQLException e) {
+			setSqlError("User", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+
+	}	
+	
+	private void closeConnection(Connection connection, GSSimStudioModel model) {
+		String error = model.getError();
+		
+		if (connection != null)
+			try {
+				connection.close();
+			} catch (SQLException e) {
+				error = model.getError();
+				if (error == null || error.equals("")) {
+					error = "Error while trying to close the SQL connection";
+				} else {
+					error += System.getProperty("line.separator");
+					error += "Error while trying to close the SQL connection";
+				}
+			}
+
+		model.setError(error);
+	}
+
+	private void setSqlError(String name, GSSimStudioModel model, Exception e) {
+		setError(name + ": an SQL exception occured while trying retrieve data from database", model, e);
+	}
+	
+	private void setDbConnectionError(GSSimStudioModel model, Exception e) {
+		setError("An exception occured while trying to create MySQLDAOFactory", model, e);
+	}
+	
+	private void setError(String messageForUser, GSSimStudioModel model, Exception e) {
+		
+		String error = messageForUser;
+		
+		if(developement)
+		{
+			error += System.getProperty("line.separator");
+			error += "Error details:";
+			error += System.getProperty("line.separator");
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			PrintStream ps = new PrintStream(baos);
+			e.printStackTrace(ps);
+			String stackTrace = baos.toString();		
+			error += stackTrace;
+		}
+		
+		model.setError(error);
+	}			
+	
+	private MySQLDAOFactory factory() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+		if(factory == null)
+			factory = new MySQLDAOFactory();
+		return factory;
+	}
+	/* END OF DB Methods */
+	
+	
+	/*******************/
+	/** GRMS3 Methods **/
+	/*******************/
+	
+	/**
+	 * Submit new GRMS job to the server. Job is described by XML structure,
+	 * which defines what application should be runned, what arguments
+	 * should be passed and where to store the resulting output.
+	 * 
+	 * @param grmsURL			address of GRMS server
+	 * @param grmsDN			DN of GRMS server
+	 * @param jobDescription	formatted XML text with the job description
+	 */
+	@BlazeDsMethod()
+	public GSSimStudioModel doSubmitApplication(String grmsURL, String grmsDN, String jobDescription) {
+
+		GSSimStudioModel model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		model.setGrmsDN(grmsDN);
+		model.setGrmsURL(grmsURL);
+		//avoid updating experiment list in archive when nothing changed
+		model.setExperimentListChanged(true);
+
+		GRMS3Job grms3job = null;
+		try {
+			grms3job = callGRMS3SubmitJob(jobDescription, grmsDN, grmsURL);
+		} catch (Exception e) {
+			model.setErrorDescription(VineFlexUtilClass.getResourceString(resourceBoundle, "grms3.jobnotsubmitted")
+					+ e.getMessage());
+		}
+		if ((grms3job == null) && (model.getErrorDescription() == null)) {
+			model.setErrorDescription(VineFlexUtilClass.getResourceString(resourceBoundle, "grms3.jobnotsubmittedcauseunknown"));
+		}
+
+		if (grms3job != null) {
+			//here we can get info about submitted job
+			
+			//gRMS3ClientModel.setSubmittedJob(grms3job);
+			//gRMS3ClientModel.setJobDescription(grms3job.getDescription());
+		}
+		return doGetJobList(grmsURL, grmsDN, model, 0, 5);
+	}
+	
+	/**
+	 * Get the list of already submitted jobs on GRMS server.
+	 * 
+	 * @param grmsURL			address of GRMS server
+	 * @param grmsDN			DN of GRMS server
+	 * @param model				GSSimStudioModel used to transfer data with RIA
+	 * @param jobFrom			which job should be picked first - job with ID 0 is the latest submitted job
+	 * @param jobCount			how many jobs should be listed
+	 */
+	public GSSimStudioModel doGetJobList(String grmsURL, String grmsDN, GSSimStudioModel model, int jobFrom,
+			int jobCount) {
+		if (model == null) {
+			model = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+		}
+		GRMS3ReturnType grms3ReturnType = null;
+		model.setGrmsDN(grmsDN);
+		model.setGrmsURL(grmsURL);
+		
+		try {
+			grms3ReturnType = callGRMS3GetJoblist(jobFrom, jobCount, grmsDN,
+					grmsURL);
+		} catch (Exception e) {
+			model.setErrorDescription(VineFlexUtilClass.getResourceString(resourceBoundle, "grms3.cannotgetjoblist")
+					+ e.getMessage());
+		}
+		if ((grms3ReturnType == null)
+				&& (model.getErrorDescription() == null)) {
+			model
+					.setErrorDescription(VineFlexUtilClass.getResourceString(resourceBoundle, "grms3.cannotgetjoblistcauseunknown"));
+		}
+		if (grms3ReturnType != null) {
+			List<GRMS3Job> grms3jobs = grms3ReturnType.getChildren();
+			//gRMS3ClientModel.setJobCount(grms3ReturnType.getJobCount());
+			//gRMS3ClientModel.setJobList(grms3jobs);
+		}
+		return model;
+	}
+	
+	/**
+	 * Calls SubmitJob on GRMS server.
+	 */
+	protected GRMS3Job callGRMS3SubmitJob(String jobDescription, String grmsDN,
+			String grmsURL) throws Exception {
+		GRMS3ClientModule gRMS3ClientModule = getGRMS3ClientModule(VineFlexUtilClass
+				.getServiceContext());
+		GRMS3Job gRMS3ClientJob = gRMS3ClientModule.submitJob(jobDescription,
+				grmsDN, grmsURL);
+		return gRMS3ClientJob;
+	}
+
+	/**
+	 * Calls GetJoblist on GRMS server.
+	 */
+	protected GRMS3ReturnType callGRMS3GetJoblist(int jobFrom, int jobCount,
+			String grmsDN, String grmsURL) throws Exception {
+		GRMS3ClientModule gRMS3ClientModule = getGRMS3ClientModule(VineFlexUtilClass
+				.getServiceContext());
+
+		return gRMS3ClientModule.getJobList(jobFrom, jobCount, grmsDN, grmsURL);
+	}
+	
+	/**
+	 * Loads GRMS Client Module from resources, which is used to connect to GRMS server. 
+	 */
+	protected GRMS3ClientModule getGRMS3ClientModule(
+			ServiceContext serviceContext) {
+		ResourceManager rm = serviceContext.createResourceManager();
+		List GRMS3ClientResourceList = rm
+				.getResourcesByType(GRMS3ClientResource.KEY);
+		if (GRMS3ClientResourceList.size() > 0) {
+			log.debug("getGRMS3ClientModule: GRMS3ClientResourceList len: "
+					+ GRMS3ClientResourceList.size());
+
+			GRMS3ClientResource gRMS3ClientResource = (GRMS3ClientResource) GRMS3ClientResourceList
+					.get(0);
+			return (GRMS3ClientModule) gRMS3ClientResource
+					.createResourceModule(GRMS3ClientModule.KEY, serviceContext);
+		} else {
+			log.error("getGRMS3ClientModule: no " + GRMS3ClientResource.KEY
+					+ " found in domain.xml");
+			return null;
+		}
+	}
+	/**************************/
+	/** END OF GRMS3 Methods **/
+	/**************************/
+	
+	/*****************************/
+	/** FILE MANAGEMENT Methods **/
+	/*****************************/
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel allWorkloadFilesUploaded() throws IOException {
+		return allFilesUploaded("gssim/input/workloads/");
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel allTopologiesFilesUploaded() throws IOException {
+		return allFilesUploaded("gssim/input/topologies/");
+	}
+	
+	@BlazeDsMethod()
+	public GSSimStudioModel allResourcesFilesUploaded() throws IOException {
+		return allFilesUploaded("gssim/input/resources/");
+	}
+	
+	@BlazeDsMethod()
+    public GSSimStudioModel allFilesUploaded(String destinationPath) throws IOException {
+
+        log.debug("FILELISTCOM all files uploaded");
+
+        GSSimStudioModel fileListComModel = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+        Vector<FileItem> uploadedFiles = VineFlexUtilClass.getUploadedFiles();
+        //avoid updating experiment list in archive when nothing changed
+        fileListComModel.setExperimentListChanged(false);
+
+        int numOfFiles = uploadedFiles.size();
+        System.out.println("FILELISTCOM all files uploaded");
+        
+
+        //String workflowName = uploadedFiles.get(0).getName();
+
+        ServiceContext serviceContext = VineFlexUtilClass.getServiceContext();
+
+        FileResourceManager fileResourceManager = getFileResourceManager(serviceContext);
+
+        Location resourceLocation = new Location((String) fileListComModel.getCurrentLocationItem().get("url"));
+
+        FileManager fileManager = fileResourceManager.createFileManager(resourceLocation);
+
+        //FileSystemManager portalFileSystemManager = VineFlexUtilClass.getPortalFileSystemManager();
+
+        fileManager.changeDirectory((String) fileListComModel.getCurrentLocationItem().get("real_path"));
+
+        Vector<FileItem> filesList = new Vector();
+        for (int a = 0; a < numOfFiles; a++) {
+        	filesList.add(uploadedFiles.get(a));
+        }
+        if (fileManager instanceof FileSystemManager) {
+            for (int i = 0; i < numOfFiles; i++) {
+            	int index = uploadedFiles.indexOf(filesList.get(i));
+            	if(index > -1){
+            		String targetpath = (String) fileListComModel.getCurrentLocationItem().get("path");
+                	//targetpath += uploadedFiles.get(i).getName();
+                    targetpath += filesList.get(i).getName();
+                    if (targetpath.startsWith("/")) {
+                        targetpath = targetpath.substring(1);
+                    }
+                    boolean tmp = VineFlexUtilClass.moveFileItemToPortalFileSystem(uploadedFiles, index, targetpath);
+                    log.debug("move to portal file system result " + tmp);
+            	}
+            }
+        } else {
+            FileSystemManager portalFileSystemManager = VineFlexUtilClass.getPortalFileSystemManager();
+
+            String tmpDir = "tmp" + String.valueOf(new Date().getTime());
+
+            String realTmpDir = portalFileSystemManager.getRealPath(tmpDir);
+
+            TaskMonitor tm = portalFileSystemManager.makeDirectory(tmpDir, TaskOptions.block());
+
+            if (!tm.completed()) {
+                throw new TaskException("error making tmp dir");
+            }
+
+            for (int i = 0; i < numOfFiles; i++) {
+            	int index = uploadedFiles.indexOf(filesList.get(i));
+            	if(index > -1){
+            		//String fileName = uploadedFiles.get(i).getName();
+            		String fileName = filesList.get(i).getName();
+            		String targetPath = tmpDir + "/" + fileName;
+            		boolean tmp = VineFlexUtilClass.moveFileItemToPortalFileSystem(uploadedFiles, i, targetPath);
+            		if (tmp) {
+            			try {
+            				String tmpTargetPath = targetPath.replace(tmpDir, realTmpDir);
+            				//log.debug("!!! src"+tmpTargetPath);
+            				//targetLocation.setFileName(fileName);
+            				String destPath = (String) fileListComModel.getCurrentLocationItem().get("path") + destinationPath;
+            				if (destPath.endsWith("/")) {
+            					destPath += fileName;
+            				} else {
+            					destPath += "/" + fileName;
+            				}
+            				FileLocation targetLocation = new FileLocation();
+            				targetLocation.setQueryItem(FileLocation.QUERY_ITEM_FILE_PATH, destPath);
+            				//log.debug("!!!!!! dest"+destPath);
+            				TaskMonitor tmpTaskMon = fileManager.upload(tmpTargetPath, targetLocation, TaskOptions.block());
+            				//log.debug("!!! called upload");
+            				if (tmpTaskMon.completed()) {
+            					log.debug("allFilesUploaded() upload successful");
+            				} else if (tmpTaskMon.failed()) {
+            					log.debug("allFilesUploaded() upload failed");
+            				} else {
+            					log.debug("allFilesUploaded() upload unexpected status");
+            				}
+            			} catch (Throwable e) {
+            				log.debug("allFilesUploaded() " + e.getMessage());
+            				log.debug("allFilesUploaded() " + e.getClass().getName());
+            			} finally {
+            				final FileLocation tmpLocation = portalFileSystemManager.createDirLocation(tmpDir);
+            				log.debug("!!!!!" + tmpLocation.getUrl());
+            				FileSet delSet = new FileLocationSet(new ArrayList<FileLocation>() {
+            					{
+            						add(tmpLocation);
+            					}
+            				});
+            				TaskMonitor delMon = portalFileSystemManager.delete(delSet, TaskOptions.block());
+            				if (delMon.completed()) {
+            					log.debug("!!!!! tmp dir was deleted");
+            				} else {
+            					log.debug("!!!!! tmp dir was NOT deleted");
+            				}
+
+            			}
+
+            		}
+            		//log.debug("move to portal file system temp result "+tmp);
+            	}
+            }
+        }
+        ///MOJE
+
+        //create workflow directory structure
+
+        //ServiceContext serviceContext = VineFlexUtilClass.getServiceContext();
+
+        //FileResourceManager fileResourceManager = getFileResourceManager(serviceContext);
+
+        loadFileLocationItems(fileListComModel, fileResourceManager, (String) fileListComModel.getCurrentLocationItem().get("url"));
+        //listWorkflows(workflowManagerAppModel);
+
+        return fileListComModel;
+    }
+	
+    public GSSimStudioModel uploadTextFile(String destFileName, String destFolder, String fileContent) throws IOException {
+
+        log.debug("FILELISTCOM all files uploaded");
+
+        GSSimStudioModel fileListComModel = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+        //avoid updating experiment list in archive when nothing changed
+		fileListComModel.setExperimentListChanged(false);
+        Vector<FileItem> uploadedFiles = new Vector<FileItem>();
+		File rootDir = new File(System.getProperty("java.io.tmpdir"));
+		FileItem item = new DiskFileItem("fieldName", null, false, destFileName, 10*1000*1000, rootDir);
+		OutputStreamWriter writer = new OutputStreamWriter(item.getOutputStream());
+		writer.write(fileContent, 0, fileContent.length());
+		writer.close();
+		uploadedFiles.add(item);
+
+        int numOfFiles = uploadedFiles.size();
+        System.out.println("FILELISTCOM all files uploaded");
+        ServiceContext serviceContext = VineFlexUtilClass.getServiceContext();
+        FileResourceManager fileResourceManager = getFileResourceManager(serviceContext);
+        Location resourceLocation = new Location((String) fileListComModel.getCurrentLocationItem().get("url"));
+        FileManager fileManager = fileResourceManager.createFileManager(resourceLocation);
+        fileManager.changeDirectory((String) fileListComModel.getCurrentLocationItem().get("real_path"));
+
+        Vector<FileItem> filesList = new Vector();
+        for (int a = 0; a < numOfFiles; a++) {
+        	filesList.add(uploadedFiles.get(a));
+        }
+        if (fileManager instanceof FileSystemManager) {
+            for (int i = 0; i < numOfFiles; i++) {
+            	int index = uploadedFiles.indexOf(filesList.get(i));
+            	if(index > -1){
+            		String targetpath = (String) fileListComModel.getCurrentLocationItem().get("path");
+                    targetpath += filesList.get(i).getName();
+                    if (targetpath.startsWith("/")) {
+                        targetpath = targetpath.substring(1);
+                    }
+                    boolean tmp = VineFlexUtilClass.moveFileItemToPortalFileSystem(uploadedFiles, index, targetpath);
+                    log.debug("move to portal file system result " + tmp);
+            	}
+            }
+        } else {
+            FileSystemManager portalFileSystemManager = VineFlexUtilClass.getPortalFileSystemManager();
+
+            String tmpDir = "tmp" + String.valueOf(new Date().getTime());
+
+            String realTmpDir = portalFileSystemManager.getRealPath(tmpDir);
+
+            TaskMonitor tm = portalFileSystemManager.makeDirectory(tmpDir, TaskOptions.block());
+
+            if (!tm.completed()) {
+                throw new TaskException("error making tmp dir");
+            }
+
+            for (int i = 0; i < numOfFiles; i++) {
+            	int index = uploadedFiles.indexOf(filesList.get(i));
+            	if(index > -1){
+            		String fileName = filesList.get(i).getName();
+            		String targetPath = tmpDir + "/" + fileName;
+            		boolean tmp = VineFlexUtilClass.moveFileItemToPortalFileSystem(uploadedFiles, i, targetPath);
+            		if (tmp) {
+            			try {
+            				String tmpTargetPath = targetPath.replace(tmpDir, realTmpDir);
+            				String destPath = (String) fileListComModel.getCurrentLocationItem().get("path") + "gssim/input/" + destFolder;
+            				if (destPath.endsWith("/")) {
+            					destPath += fileName;
+            				} else {
+            					destPath += "/" + fileName;
+            				}
+            				FileLocation targetLocation = new FileLocation();
+            				targetLocation.setQueryItem(FileLocation.QUERY_ITEM_FILE_PATH, destPath);
+            				TaskMonitor tmpTaskMon = fileManager.upload(tmpTargetPath, targetLocation, TaskOptions.block());
+            				if (tmpTaskMon.completed()) {
+            					log.debug("allFilesUploaded() upload successful");
+            				} else if (tmpTaskMon.failed()) {
+            					log.debug("allFilesUploaded() upload failed");
+            				} else {
+            					log.debug("allFilesUploaded() upload unexpected status");
+            				}
+            			} catch (Throwable e) {
+            				log.debug("allFilesUploaded() " + e.getMessage());
+            				log.debug("allFilesUploaded() " + e.getClass().getName());
+            			} finally {
+            				final FileLocation tmpLocation = portalFileSystemManager.createDirLocation(tmpDir);
+            				log.debug("!!!!!" + tmpLocation.getUrl());
+            				FileSet delSet = new FileLocationSet(new ArrayList<FileLocation>() {
+            					{
+            						add(tmpLocation);
+            					}
+            				});
+            				TaskMonitor delMon = portalFileSystemManager.delete(delSet, TaskOptions.block());
+            				if (delMon.completed()) {
+            					log.debug("!!!!! tmp dir was deleted");
+            				} else {
+            					log.debug("!!!!! tmp dir was NOT deleted");
+            				}
+
+            			}
+
+            		}
+            	}
+            }
+        }
+        
+        loadFileLocationItems(fileListComModel, fileResourceManager, (String) fileListComModel.getCurrentLocationItem().get("url"));
+
+        return fileListComModel;
+    }
+	
+	@BlazeDsMethod()
+    public GSSimStudioModel uploadPropertyFile(String destFileName, String fileContent) throws IOException {
+		return uploadTextFile(destFileName, "", fileContent);
+    }
+	
+	@BlazeDsMethod()
+    public GSSimStudioModel uploadNetworkTopologyFile(String destFileName, String fileContent) throws IOException {
+		return uploadTextFile(destFileName, "topologies/", fileContent);
+    }
+	
+	@BlazeDsMethod()
+    public GSSimStudioModel uploadResourceFile(String destFileName, String fileContent) throws IOException {
+		return uploadTextFile(destFileName, "resources/", fileContent);
+    }
+	
+	public void loadFileLocationItems(GSSimStudioModel fileListComModel, FileManager fileManager, String fileLocationUrl) throws IOException {
+
+        log.debug("loadFileLocationItems " + fileLocationUrl);
+        
+        String url = "gsiftp://grass1.man.poznan.pl:2811/home/mcichenski/gssim/input/workloads/?filetype=directory";
+        
+        // Create file location for url
+        FileLocation folderLocation = new FileLocation(url);
+
+        // Change location
+        //todo tu jest lipa
+        fileManager.changeLocation(folderLocation);
+
+        // List workload files
+        ArrayList<HashMap> fileLocationItemList = new ArrayList<HashMap>();
+        fileListComModel.setWorkloadFileLocationItemList(fileLocationItemList);
+        loadFileLocationItemsForCurrentLocation(fileListComModel, fileManager, fileLocationItemList);
+        
+      //List topology files
+        url = "gsiftp://grass1.man.poznan.pl:2811/home/mcichenski/gssim/input/topologies/?filetype=directory";
+        folderLocation = new FileLocation(url);
+        fileManager.changeLocation(folderLocation);
+        fileLocationItemList = new ArrayList<HashMap>();
+        fileListComModel.setTopologiesFileLocationItemList(fileLocationItemList);
+        loadFileLocationItemsForCurrentLocation(fileListComModel, fileManager, fileLocationItemList);
+        
+        //List resource files
+        url = "gsiftp://grass1.man.poznan.pl:2811/home/mcichenski/gssim/input/resources/?filetype=directory";
+        folderLocation = new FileLocation(url);
+        fileManager.changeLocation(folderLocation);
+        fileLocationItemList = new ArrayList<HashMap>();
+        fileListComModel.setResourcesFileLocationItemList(fileLocationItemList);
+        loadFileLocationItemsForCurrentLocation(fileListComModel, fileManager, fileLocationItemList);
+        
+        //reset current location
+        url = "gsiftp://grass1.man.poznan.pl:2811/home/mcichenski/?filetype=directory";
+        folderLocation = new FileLocation(url);
+        fileManager.changeLocation(folderLocation);
+        HashMap<String, String> currentLocationItem = new HashMap<String, String>();
+        fileListComModel.setCurrentLocationItem(currentLocationItem);
+        currentLocationItem.put("real_path", folderLocation.getFilePath());
+        currentLocationItem.put("path", fileManager.getCurrentDirectory());
+        currentLocationItem.put("url", folderLocation.getUrl());
+        currentLocationItem.put("downloadUrl", VineFlexUtilClass.getDownloadURL(folderLocation));
+    }
+
+    public void loadFileLocationItems(GSSimStudioModel fileListComModel, FileResourceManager fileResourceManager, String fileLocationUrl) throws IOException {
+        log.debug("loadFileLocationItems" + fileLocationUrl);
+
+        String url = "gsiftp://grass1.man.poznan.pl:2811/home/mcichenski/gssim/input/workloads/?filetype=directory";
+        
+        // Create file location for url
+        FileLocation folderLocation = new FileLocation(url);
+
+        // Get file manager for given location
+        //TODO: nie dziala dla gria
+        FileManager fileManager = fileResourceManager.createFileManager(folderLocation);
+
+        // List workload files
+        ArrayList<HashMap> fileLocationItemList = new ArrayList<HashMap>();
+        fileListComModel.setWorkloadFileLocationItemList(fileLocationItemList);
+        loadFileLocationItemsForCurrentLocation(fileListComModel, fileManager, fileLocationItemList);
+        
+        //List topology files
+        url = "gsiftp://grass1.man.poznan.pl:2811/home/mcichenski/gssim/input/topologies/?filetype=directory";
+        folderLocation = new FileLocation(url);
+        fileManager = fileResourceManager.createFileManager(folderLocation);
+        fileLocationItemList = new ArrayList<HashMap>();
+        fileListComModel.setTopologiesFileLocationItemList(fileLocationItemList);
+        loadFileLocationItemsForCurrentLocation(fileListComModel, fileManager, fileLocationItemList);
+        
+        //List resource files
+        url = "gsiftp://grass1.man.poznan.pl:2811/home/mcichenski/gssim/input/resources/?filetype=directory";
+        folderLocation = new FileLocation(url);
+        fileManager = fileResourceManager.createFileManager(folderLocation);
+        fileLocationItemList = new ArrayList<HashMap>();
+        fileListComModel.setResourcesFileLocationItemList(fileLocationItemList);
+        loadFileLocationItemsForCurrentLocation(fileListComModel, fileManager, fileLocationItemList);
+        
+        //reset current location
+        url = "gsiftp://grass1.man.poznan.pl:2811/home/mcichenski/?filetype=directory";
+        folderLocation = new FileLocation(url);
+        fileManager = fileResourceManager.createFileManager(folderLocation);
+        HashMap<String, String> currentLocationItem = new HashMap<String, String>();
+        fileListComModel.setCurrentLocationItem(currentLocationItem);
+        currentLocationItem.put("real_path", folderLocation.getFilePath());
+        currentLocationItem.put("path", fileManager.getCurrentDirectory());
+        currentLocationItem.put("url", folderLocation.getUrl());
+        currentLocationItem.put("downloadUrl", VineFlexUtilClass.getDownloadURL(folderLocation));
+    }
+	
+	public void loadFileLocationItemsForCurrentLocation(GSSimStudioModel fileListComModel, FileManager fileManager, ArrayList<HashMap> fileLocationItemList) throws IOException {
+
+        log.debug("loadFileLocationItemsForCurrentLocation");
+
+        try {
+
+            // Update current folder location
+            FileLocation folderLocation = fileManager.getCurrentLocation();
+
+            // Current location item
+            HashMap<String, String> currentLocationItem = new HashMap<String, String>();
+            fileListComModel.setCurrentLocationItem(currentLocationItem);
+
+            currentLocationItem.put("real_path", folderLocation.getFilePath());
+            currentLocationItem.put("path", fileManager.getCurrentDirectory());
+            currentLocationItem.put("url", folderLocation.getUrl());
+            currentLocationItem.put("downloadUrl", VineFlexUtilClass.getDownloadURL(folderLocation));
+
+            // List files in defafult directory
+            List<? extends FileLocation> fileLocationList;
+            try {
+
+                fileLocationList = fileManager.list();
+
+            } catch (Exception e) {
+                log.error("Error occured during list", e);
+                return;
+            }
+
+            //String fileDownloadServletUrl = FileDownloadServlet.getResourceUrl();
+
+            for (FileLocation fileLocation : fileLocationList) {
+
+                HashMap<String, String> fileLocationItem = new HashMap<String, String>();
+                fileLocationItemList.add(fileLocationItem);
+
+                // File url (not displayed?)
+                String fileUrl = fileLocation.getUrl();
+                fileLocationItem.put("fileUrl", fileUrl);
+
+                String fileUrlWithoutQuery = fileLocation.getUrlWithoutQuery();
+                fileLocationItem.put("fileUrlWithoutQuery", fileUrlWithoutQuery);
+
+                // File name
+                String fileName = fileLocation.getFileName();
+                fileLocationItem.put("fileName", fileName);
+
+                // File type
+                FileType fileType = fileLocation.getFileType();
+                fileLocationItem.put("fileType", fileType.getName());
+
+                // Date modified column
+
+                long dateLastModified = fileLocation.getDateLastModified();
+
+                fileLocationItem.put("dateModified", String.valueOf(dateLastModified));
+
+                // Date modified column
+                //fileLocationItem.put("dateModifiedText", DateUtil.getLocalizedDate(dateLastModified, DateFormat.MEDIUM, DateFormat.MEDIUM));
+
+                // File size column
+                long fileSize = fileLocation.getFileSize();
+                fileLocationItem.put("fileSize", String.valueOf(fileSize));
+
+                // File size column
+                fileLocationItem.put("fileSizeText", String.valueOf(fileSize) + " bytes");
+
+                fileLocationItem.put("folderUrl", folderLocation.getUrl());
+                
+                // Download url
+                if (fileType.equals(FileType.FILE)) {
+                    //fileLocationItem.put("fileDownloadUrl", FileDownloadServlet.getResourceUrlForFileLocation(fileLocation, false));
+                }
+            }
+
+            log.debug("done");
+
+        } catch (Exception e) {
+            log.error("Exception occurred during loadFileLocationGrid", e);
+        }
+    }
+	
+	@BlazeDsMethod()
+    public GSSimStudioModel deleteFileItem(String fileItemUrl, String currentUrl) throws IOException {
+
+        log.debug("deleteFileItem");
+
+        GSSimStudioModel fileListComModel = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+        //avoid updating experiment list in archive when nothing changed
+		fileListComModel.setExperimentListChanged(false);
+
+        try {
+
+            ServiceContext serviceContext = VineFlexUtilClass.getServiceContext();
+
+            FileResourceManager fileResourceManager = getFileResourceManager(serviceContext);
+
+            FileLocation currentLocation = new FileLocation(currentUrl);
+
+            FileManager fileManager = fileResourceManager.createFileManager(currentLocation);
+
+            final FileLocation fileItemLocation = new FileLocation(fileItemUrl);
+
+            FileSet fileSet = new FileLocationSet(new ArrayList<FileLocation>() {
+                {
+                    add(fileItemLocation);
+                }
+            });
+
+            TaskMonitor taskMonitor = fileManager.delete(fileSet, TaskOptions.block());
+
+            if (taskMonitor.completed()) {
+                // DO NOTHING FOR NOW
+            } else if (taskMonitor.failed()) {
+                String message = taskMonitor.getTaskStatusMessage();
+                //fileListComModel.setError(createErrorMap("deleteFileItem", "Task failed " + message));
+            } else {
+                log.debug("Task returned with unexpected status: " + taskMonitor.getTaskStatus().getLabel());
+                //fileListComModel.setError(createErrorMap("Task returned with unexpected status: ", taskMonitor.getTaskStatus().getLabel()));
+            }
+
+            // Reload file location items and current location
+
+            loadFileLocationItems(fileListComModel, fileManager, currentUrl);
+
+        } catch (MalformedURLException e) {
+            log.error("Error ocurred in deleteFile", e);
+            //fileListComModel.setError(createErrorMap("Error ocurred in deleteFile: ", e.getMessage()));
+        }
+
+        return fileListComModel;
+
+    }
+	
+	private HashMap<String, String> createErrorMap(String method, String message) {
+        HashMap<String, String> res = new HashMap<String, String>();
+        res.put("method", method);
+        res.put("message", message);
+        res.put("timestamp", String.valueOf(new Date().getTime()));
+        return res;
+    }
+	
+	@BlazeDsMethod()
+    public Object init(Object model) {
+        log.debug("init() called");
+		GSSimStudioModel gssimStudioModel = (GSSimStudioModel) model;
+		//avoid updating experiment list in archive when nothing changed
+		gssimStudioModel.setExperimentListChanged(false);
+		if (gssimStudioModel == null)
+			gssimStudioModel = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+        initFileManagerModel(gssimStudioModel);
+        getPluginsFromDb(gssimStudioModel);
+        return getExperimentsFromDb(gssimStudioModel, null, null, null);
+    }
+	
+	@BlazeDsMethod()
+    public Object reinit(Object model) {
+        return init(model);
+    }
+
+    @BlazeDsMethod()
+    public Object clientRebound(Object model) {
+        return init(model);
+    }
+	
+	public void initFileManagerModel(GSSimStudioModel gssimStudioModel) {
+        ServiceContext serviceContext = VineFlexUtilClass.getServiceContext();
+        initFileManagerModel(gssimStudioModel, serviceContext);
+    }
+	
+	public void initFileManagerModel(GSSimStudioModel gssimStudioModel, ServiceContext serviceContext) {
+
+        log.debug("initFileManagerModel");
+
+        try {
+            // Get file resource manager
+            FileResourceManager fileResourceManager = getFileResourceManager(serviceContext);
+
+            // Build favorite and server location lists, return default location to list
+
+            String currentUrl = (String) gssimStudioModel.getCurrentLocationItem().get("url");
+
+            log.debug("Stored current location url: " + currentUrl);
+
+            String defaultLocationUrl = loadLinkAndServerItems(gssimStudioModel, fileResourceManager, currentUrl);
+			log.debug("Stored current location url: " + defaultLocationUrl);
+			
+			// Load file location items and current location
+            loadFileLocationItems(gssimStudioModel, fileResourceManager, defaultLocationUrl);
+
+        } catch (Exception e) {
+            log.error("Error ocurred in initFileManagerModel", e);
+//            loadErrorMessage(e, "An error occured");
+        }
+    }
+	
+	public String loadLinkAndServerItems(GSSimStudioModel gssimStudioModel, FileResourceManager fileResourceManager, String fileLocationUrl) throws MalformedURLException {
+
+        // Get file resource list
+        List<? extends FileResource> fileResourceList = fileResourceManager.getFileResources();
+
+        String defaultLocationUrl = fileLocationUrl;
+
+        // Build link location list
+        ArrayList<HashMap> linkLocationItemList = new ArrayList<HashMap>();
+        gssimStudioModel.setLinkLocationItemList(linkLocationItemList);
+
+        for (FileResource fileResource : fileResourceList) {
+
+            if (fileResource instanceof FileSystemResource) {
+
+                HashMap<String, String> linkLocationItem = new HashMap<String, String>();
+                linkLocationItemList.add(linkLocationItem);
+
+                String homeLocationUrl = fileResource.getLocation().getUrl();
+
+                linkLocationItem.put("label", "Home");
+                linkLocationItem.put("url", homeLocationUrl);
+
+                // Set default location url if not already set
+                if (defaultLocationUrl == null) {
+
+                    linkLocationItem.put("selected", "true");
+                }
+
+            }
+        }
+
+        //  Build server location list
+        ArrayList<HashMap> serverLocationItemList = new ArrayList<HashMap>();
+        gssimStudioModel.setServerLocationItemList(serverLocationItemList);
+
+        boolean isSelected = false;
+
+        for (FileResource fileResource : fileResourceList) {
+
+            HashMap<String, String> serverLocationItem = new HashMap<String, String>();
+
+            String serverLocationLabel = fileResource.getLabel();
+			
+			//FIXME: nie powinno byï¿œ po nazwie
+			if (serverLocationLabel.equals("Portal File System")) continue;
+			serverLocationItemList.add(serverLocationItem);
+			
+            String serverLocationUrl = fileResource.getLocation().getUrl();
+
+            serverLocationItem.put("label", serverLocationLabel);
+            serverLocationItem.put("url", serverLocationUrl);
+
+            // Set default location url if not already set
+            if (defaultLocationUrl == null) {
+
+                isSelected = true;
+
+                serverLocationItem.put("selected", "true");
+                defaultLocationUrl = serverLocationUrl;
+
+
+            }
+		}
+
+        return defaultLocationUrl;
+    }
+	
+	@BlazeDsMethod()
+    public GSSimStudioModel browseResource(String resourceUrl, int selectedServerIdx) throws IOException {
+
+        log.debug("browseResource() called");
+
+        ServiceContext serviceContext = VineFlexUtilClass.getServiceContext();
+
+        GSSimStudioModel fileListComModel = (GSSimStudioModel) VineFlexUtilClass.getUIModel();
+
+        //avoid updating experiment list in archive when nothing changed
+		fileListComModel.setExperimentListChanged(false);
+        
+        FileResourceManager fileResourceManager = getFileResourceManager(serviceContext);
+
+        Iterator<HashMap> it = fileListComModel.getServerLocationItemList().iterator();
+
+        fileListComModel.setSelectedServerIdx(selectedServerIdx);
+
+        int cnt = 0;
+
+        while (it.hasNext()) {
+            HashMap<String, String> tmp = it.next();
+            if (tmp.containsKey("selected")) {
+                tmp.remove("selected");
+            }
+            if (tmp.get("url").equals(resourceUrl)) {
+
+                tmp.put("selected", "true");
+                //fileListComModel.setSelectedServerIdx(cnt);
+                //zapamietaj zaznaczony?
+            }
+            cnt++;
+        }
+
+        loadFileLocationItems(fileListComModel, fileResourceManager, resourceUrl);
+
+        return fileListComModel;
+
+    }
+	
+	public static FileResourceManager getFileResourceManager(ServiceContext serviceContext) {
+        return (FileResourceManager) serviceContext.createService(FileResourceManager.KEY);
+    }
+	
+	public long guestUploadSizeLimit() {
+        return 1*1024*1024*1024;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public int guestUploadFilesLimit() {
+        return 5;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public long loggedInUploadSizeLimit(Principal principal) {
+        return -1;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public int loggedInUploadFilesLimit(Principal principal) {
+        return -1;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+    /**************************/
+	/** END OF File Manager Methods **/
+	/**************************/
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ResourceChartModel.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ResourceChartModel.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ResourceChartModel.java	(revision 15)
@@ -0,0 +1,89 @@
+package gssim.gssimstudio.flex.app.editor;
+
+import java.io.Serializable;
+import org.vinetoolkit.grms3client.GRMS3Job;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import gssim.db.dao.data.Allocation;
+import gssim.db.dao.data.AllocationDetails;
+import gssim.db.dao.data.BlobProperty;
+import gssim.db.dao.data.Configuration;
+import gssim.db.dao.data.Metaexperiment;
+import gssim.db.dao.data.Experiment;
+import gssim.db.dao.data.ExperimentStats;
+import gssim.db.dao.data.Queues;
+import gssim.db.dao.data.Plugin;
+import gssim.db.dao.data.Reservation;
+import gssim.db.dao.data.ReservationDetails;
+import gssim.db.dao.data.Resource;
+import gssim.db.dao.data.ResourceAllTimeline;
+import gssim.db.dao.data.ResourceEnTimeline;
+import gssim.db.dao.data.Task;
+import gssim.db.dao.data.TextProperty;
+import gssim.db.dao.data.Unit;
+import gssim.db.dao.data.UnitAllTimeline;
+import gssim.db.dao.data.UnitDetails;
+import gssim.db.dao.data.UnitEnTimeline;
+import gssim.db.dao.data.User;
+
+/*
+ * @author Mateusz Cicheï¿œski, Jarek Szymczak
+ */
+public class ResourceChartModel implements Serializable {
+
+    //    IMPORTANT - please regenerate your serialVersionUID
+    private static final long serialVersionUID = 5436766887639900888L;
+	
+	/* FIELDS FOR DB DATA */
+    
+    private Integer selectedResourceIndex;
+	private String error;
+	private List<Resource> resourceList;
+	private List resourceTimelineList;
+	private HashMap<String, String> experimentConfiguration;
+	/* END OF DB DATA */
+
+	public Integer getSelectedResourceIndex() {
+		return selectedResourceIndex;
+	}
+	
+	public void setSelectedResourceIndex(Integer index) {
+		this.selectedResourceIndex = index;
+	}
+	
+	public String getError() {
+		return error;
+	}
+
+	public void setError(String error) {
+		this.error = error;
+	}
+	
+	public List<Resource> getResourceList() {
+		return resourceList;
+	}
+
+	public void setResourceList(List<Resource> resourceList) {
+		this.resourceList = resourceList;
+	}
+
+	public List getResourceTimelineList() {
+		return resourceTimelineList;
+	}
+
+	public void setResourceTimelineList(
+			List resourceTimelineList) {
+		this.resourceTimelineList = resourceTimelineList;
+	}
+
+	public HashMap<String, String> getExperimentConfiguration() {
+		return experimentConfiguration;
+	}
+
+	public void setExperimentConfiguration(
+			HashMap<String, String> experimentConfiguration) {
+		this.experimentConfiguration = experimentConfiguration;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudioModel.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudioModel.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudioModel.java	(revision 15)
@@ -0,0 +1,378 @@
+package gssim.gssimstudio.flex.app.editor;
+
+import java.io.Serializable;
+import org.vinetoolkit.grms3client.GRMS3Job;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import gssim.db.dao.data.Allocation;
+import gssim.db.dao.data.AllocationDetails;
+import gssim.db.dao.data.BlobProperty;
+import gssim.db.dao.data.Configuration;
+import gssim.db.dao.data.Metaexperiment;
+import gssim.db.dao.data.Experiment;
+import gssim.db.dao.data.ExperimentStats;
+import gssim.db.dao.data.Queues;
+import gssim.db.dao.data.Plugin;
+import gssim.db.dao.data.Reservation;
+import gssim.db.dao.data.ReservationDetails;
+import gssim.db.dao.data.Resource;
+import gssim.db.dao.data.ResourceAllTimeline;
+import gssim.db.dao.data.ResourceEnTimeline;
+import gssim.db.dao.data.Task;
+import gssim.db.dao.data.TextProperty;
+import gssim.db.dao.data.Unit;
+import gssim.db.dao.data.UnitAllTimeline;
+import gssim.db.dao.data.UnitDetails;
+import gssim.db.dao.data.UnitEnTimeline;
+import gssim.db.dao.data.User;
+
+/*
+ * @author Mateusz Cicheï¿œski, Jarek Szymczak
+ */
+public class GSSimStudioModel implements Serializable {
+
+    //    IMPORTANT - please regenerate your serialVersionUID
+    private static final long serialVersionUID = 5436766887639900902L;
+
+    public GSSimStudioModel() {
+    }
+    
+    private HashMap comparisonComponents = new HashMap();
+    
+    public HashMap getComparisonComponents() {
+        return comparisonComponents;
+    }
+
+    public void setComparisonComponents(HashMap comparisonComponents) {
+        this.comparisonComponents = comparisonComponents;
+    }
+    
+    private HashMap resourceChartComponents = new HashMap();
+    
+    public HashMap getResourceChartComponents() {
+        return resourceChartComponents;
+    }
+
+    public void setResourceChartComponents(HashMap resourceChartComponents) {
+        this.resourceChartComponents = resourceChartComponents;
+    }
+    
+	/* FIELDS FOR GRMS3 HANDLING */
+    public String errorDescription;
+    public String grmsDN;
+    public String grmsURL;
+	/* END OF GRMS3 HANDLING */
+	
+	/* FIELDS FOR FILE TRANSFER */
+	private ArrayList serverLocationItemList = new ArrayList();
+	private HashMap currentLocationItem = new HashMap();
+    private ArrayList linkLocationItemList = new ArrayList();
+    private ArrayList workloadFileLocationItemList = new ArrayList();
+    private ArrayList resourcesFileLocationItemList = new ArrayList();
+    private ArrayList topologiesFileLocationItemList = new ArrayList();
+	private int selectedServerIdx;
+	/* END OF FILE TRANSFER */
+	
+	/* FIELDS FOR DB DATA */
+	private String error;
+	private byte[] currentExperimentNetworkTopology;
+	private List<HashMap<String, String>> globalPluginList;
+	private List<HashMap<String, String>> localPluginList;
+	private List<Allocation> allocationList;
+	private List<AllocationDetails> allocationDetailsList;
+	private List<BlobProperty> blobPropertyList;
+	private ExtendedConfiguration extendedConfiguration;
+	private HashMap metaexperimentList = new HashMap();
+	private List<Experiment> experimentList;
+	private Boolean experimentListChanged = false;
+	private List<ExperimentStats> experimentStatsList;
+	private List<Queues> queuesList;
+	private List<Reservation> reservationList;
+	private List<ReservationDetails> reservationDetailsList;
+	private List<Task> taskList;
+	private List<TextProperty> textPropertyList;
+	private List<Unit> unitList;
+	private List<UnitAllTimeline> unitAllTimelineList;
+	private List<UnitDetails> unitDetailsList;
+	private List<UnitEnTimeline> unitEnTimelineList;
+	private User user;
+	/* END OF DB DATA */
+
+    /**
+	 * @return the grmsDN
+	 */
+	public String getGrmsDN() {
+		return grmsDN;
+	}
+
+	/**
+	 * @param grmsDN the grmsDN to set
+	 */
+	public void setGrmsDN(String grmsDN) {
+		this.grmsDN = grmsDN;
+	}
+
+	/**
+	 * @return the grmsURL
+	 */
+	public String getGrmsURL() {
+		return grmsURL;
+	}
+
+	/**
+	 * @param grmsURL the grmsURL to set
+	 */
+	public void setGrmsURL(String grmsURL) {
+		this.grmsURL = grmsURL;
+	}
+
+	/**
+	 * @return the errorDescription
+	 */
+	public String getErrorDescription() {
+		return errorDescription;
+	}
+
+	/**
+	 * @param errorDescription the errorDescription to set
+	 */
+	public void setErrorDescription(String errorDescription) {
+		this.errorDescription = errorDescription;
+	}
+	
+	public ArrayList getServerLocationItemList() {
+        return serverLocationItemList;
+    }
+
+    public void setServerLocationItemList(ArrayList serverLocationItemList) {
+        this.serverLocationItemList = serverLocationItemList;
+    }
+	
+	public HashMap getCurrentLocationItem() {
+        return currentLocationItem;
+    }
+
+    public void setCurrentLocationItem(HashMap currentLocationItem) {
+        this.currentLocationItem = currentLocationItem;
+    }
+
+    public ArrayList getLinkLocationItemList() {
+        return linkLocationItemList;
+    }
+
+    public void setLinkLocationItemList(ArrayList linkLocationItemList) {
+        this.linkLocationItemList = linkLocationItemList;
+    }
+    
+    public ArrayList getWorkloadFileLocationItemList(){
+        return workloadFileLocationItemList;
+    }
+
+    public void setWorkloadFileLocationItemList(ArrayList fileLocationItemList){
+        this.workloadFileLocationItemList=fileLocationItemList;
+    }
+    
+    public ArrayList getTopologiesFileLocationItemList(){
+        return topologiesFileLocationItemList;
+    }
+
+    public void setTopologiesFileLocationItemList(ArrayList fileLocationItemList){
+        this.topologiesFileLocationItemList=fileLocationItemList;
+    }
+    
+    public ArrayList getResourcesFileLocationItemList(){
+        return resourcesFileLocationItemList;
+    }
+
+    public void setResourcesFileLocationItemList(ArrayList fileLocationItemList){
+        this.resourcesFileLocationItemList=fileLocationItemList;
+    }
+	
+	public int getSelectedServerIdx(){
+        return selectedServerIdx;
+    }
+
+    public void setSelectedServerIdx(int selectedServerIdx){
+        this.selectedServerIdx=selectedServerIdx;
+    }
+	
+	public String getError() {
+		return error;
+	}
+
+	public void setError(String error) {
+		this.error = error;
+	}
+	
+	public byte[] getCurrentExperimentNetworkTopology() {
+		return currentExperimentNetworkTopology;
+	}
+
+	public void setCurrentExperimentNetworkTopology(byte[] currentExperimentNetworkTopology) {
+		this.currentExperimentNetworkTopology = currentExperimentNetworkTopology;
+	}
+	
+	public List<HashMap<String, String>> getGlobalPluginList() {
+		return globalPluginList;
+	}
+
+	public void setGlobalPluginList(List<HashMap<String, String>> globalPluginList) {
+		this.globalPluginList = globalPluginList;
+	}
+	
+	public List<HashMap<String, String>> getLocalPluginList() {
+		return localPluginList;
+	}
+
+	public void setLocalPluginList(List<HashMap<String, String>> localPluginList) {
+		this.localPluginList = localPluginList;
+	}
+	
+	public List<Allocation> getAllocationList() {
+		return allocationList;
+	}
+
+	public void setAllocationList(List<Allocation> allocationList) {
+		this.allocationList = allocationList;
+	}
+
+	public List<AllocationDetails> getAllocationDetailsList() {
+		return allocationDetailsList;
+	}
+
+	public void setAllocationDetailsList(
+			List<AllocationDetails> allocationDetailsList) {
+		this.allocationDetailsList = allocationDetailsList;
+	}
+
+	public List<BlobProperty> getBlobPropertyList() {
+		return blobPropertyList;
+	}
+
+	public void setBlobPropertyList(List<BlobProperty> blobPropertyList) {
+		this.blobPropertyList = blobPropertyList;
+	}
+
+	public ExtendedConfiguration getExtendedConfiguration() {
+		return extendedConfiguration;
+	}
+
+	public void setExtendedConfiguration(ExtendedConfiguration extendedConfiguration) {
+		this.extendedConfiguration = extendedConfiguration;
+	}
+
+	public HashMap getMetaexperimentList() {
+		return metaexperimentList;
+	}
+
+	public void setMetaexperimentList(HashMap metaexperimentList) {
+		this.metaexperimentList = metaexperimentList;
+	}
+	
+	public List<Experiment> getExperimentList() {
+		return experimentList;
+	}
+
+	public void setExperimentList(List<Experiment> experimentList) {
+		this.experimentList = experimentList;
+	}
+	
+	public Boolean getExperimentListChanged() {
+		return experimentListChanged;
+	}
+
+	public void setExperimentListChanged(Boolean experimentListChanged) {
+		this.experimentListChanged = experimentListChanged;
+	}
+
+	public List<ExperimentStats> getExperimentStatsList() {
+		return experimentStatsList;
+	}
+
+	public void setExperimentStatsList(List<ExperimentStats> experimentStatsList) {
+		this.experimentStatsList = experimentStatsList;
+	}
+
+	public List<Queues> getQueuesList() {
+		return queuesList;
+	}
+
+	public void setQueuesList(List<Queues> queuesList) {
+		this.queuesList = queuesList;
+	}
+
+	public List<Reservation> getReservationList() {
+		return reservationList;
+	}
+
+	public void setReservationList(List<Reservation> reservationList) {
+		this.reservationList = reservationList;
+	}
+
+	public List<ReservationDetails> getReservationDetailsList() {
+		return reservationDetailsList;
+	}
+
+	public void setReservationDetailsList(
+			List<ReservationDetails> reservationDetailsList) {
+		this.reservationDetailsList = reservationDetailsList;
+	}
+
+	public List<Task> getTaskList() {
+		return taskList;
+	}
+
+	public void setTaskList(List<Task> taskList) {
+		this.taskList = taskList;
+	}
+
+	public List<TextProperty> getTextPropertyList() {
+		return textPropertyList;
+	}
+
+	public void setTextPropertyList(List<TextProperty> textPropertyList) {
+		this.textPropertyList = textPropertyList;
+	}
+
+	public List<Unit> getUnitList() {
+		return unitList;
+	}
+
+	public void setUnitList(List<Unit> unitList) {
+		this.unitList = unitList;
+	}
+
+	public List<UnitAllTimeline> getUnitAllTimelineList() {
+		return unitAllTimelineList;
+	}
+
+	public void setUnitAllTimelineList(List<UnitAllTimeline> unitAllTimelineList) {
+		this.unitAllTimelineList = unitAllTimelineList;
+	}
+
+	public List<UnitDetails> getUnitDetailsList() {
+		return unitDetailsList;
+	}
+
+	public void setUnitDetailsList(List<UnitDetails> unitDetailsList) {
+		this.unitDetailsList = unitDetailsList;
+	}
+
+	public List<UnitEnTimeline> getUnitEnTimelineList() {
+		return unitEnTimelineList;
+	}
+
+	public void setUnitEnTimelineList(List<UnitEnTimeline> unitEnTimelineList) {
+		this.unitEnTimelineList = unitEnTimelineList;
+	}
+
+	public User getUser() {
+		return user;
+	}
+
+	public void setUser(User user) {
+		this.user = user;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExperimentComparisonChart.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExperimentComparisonChart.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExperimentComparisonChart.java	(revision 15)
@@ -0,0 +1,274 @@
+package gssim.gssimstudio.flex.app.editor;
+
+import java.io.*;
+import java.util.*;
+
+import org.vinetoolkit.ResourceManager;
+import org.vinetoolkit.ServiceContext;
+import org.vinetoolkit.Session;
+
+import org.vinetoolkit.web.spi.annotation.BlazeDsDestination;
+import org.vinetoolkit.web.spi.annotation.BlazeDsMethod;
+import org.vinetoolkit.web.flex.blazeds.shared.utils.VineFlexUtilClass;
+import org.vinetoolkit.web.portlet.spi.annotation.PortletDisplayName;
+import org.vinetoolkit.role.VineRoleManager;
+import org.vinetoolkit.spi.util.ServiceLog;
+
+import flex.messaging.FlexContext;
+import org.vinetoolkit.web.spi.annotation.BlazeDsDestination;
+import org.vinetoolkit.web.spi.annotation.BlazeDsMethod;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.disk.DiskFileItem;
+import org.vinetoolkit.io.*;
+import org.vinetoolkit.io.sets.FileLocationSet;
+import org.vinetoolkit.ServiceContext;
+import org.vinetoolkit.Location;
+import org.vinetoolkit.task.TaskMonitor;
+import org.vinetoolkit.task.TaskOptions;
+import org.vinetoolkit.task.TaskException;
+import org.vinetoolkit.localhost.io.FileSystemResource;
+import org.vinetoolkit.localhost.io.FileSystemManager;
+import org.vinetoolkit.spi.util.ServiceLog;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+
+import org.vinetoolkit.web.flex.blazeds.shared.uibackend.ModelInitialization;
+import org.vinetoolkit.web.flex.blazeds.shared.uibackend.FileUploadAccepter;
+import java.security.Principal;
+
+import gssim.db.dao.data.Allocation;
+import gssim.db.dao.data.AllocationDetails;
+import gssim.db.dao.data.BlobProperty;
+import gssim.db.dao.data.Configuration;
+import gssim.db.dao.data.Metaexperiment;
+import gssim.db.dao.data.Experiment;
+import gssim.db.dao.data.ExperimentStats;
+import gssim.db.dao.data.Queues;
+import gssim.db.dao.data.Plugin;
+import gssim.db.dao.data.PluginCompatibility;
+import gssim.db.dao.data.Reservation;
+import gssim.db.dao.data.ReservationDetails;
+import gssim.db.dao.data.Resource;
+import gssim.db.dao.data.ResourceAllTimeline;
+import gssim.db.dao.data.ResourceEnTimeline;
+import gssim.db.dao.data.Task;
+import gssim.db.dao.data.TextProperty;
+import gssim.db.dao.data.Unit;
+import gssim.db.dao.data.UnitAllTimeline;
+import gssim.db.dao.data.UnitDetails;
+import gssim.db.dao.data.UnitEnTimeline;
+import gssim.db.dao.data.User;
+import gssim.db.find.Finder;
+import gssim.db.mysql.AllocationDAO;
+import gssim.db.mysql.AllocationDetailsDAO;
+import gssim.db.mysql.BlobPropertyDAO;
+import gssim.db.mysql.ConfigurationDAO;
+import gssim.db.mysql.ExperimentDAO;
+import gssim.db.mysql.MetaexperimentDAO;
+import gssim.db.mysql.ExperimentStatsDAO;
+import gssim.db.mysql.MySQLDAOFactory;
+import gssim.db.mysql.QueuesDAO;
+import gssim.db.mysql.PluginDAO;
+import gssim.db.mysql.PluginCompatibilityDAO;
+import gssim.db.mysql.ReservationDAO;
+import gssim.db.mysql.ReservationDetailsDAO;
+import gssim.db.mysql.ResourceAllTimelineDAO;
+import gssim.db.mysql.ResourceDAO;
+import gssim.db.mysql.ResourceEnTimelineDAO;
+import gssim.db.mysql.TaskDAO;
+import gssim.db.mysql.TextPropertyDAO;
+import gssim.db.mysql.UnitAllTimelineDAO;
+import gssim.db.mysql.UnitDAO;
+import gssim.db.mysql.UnitDetailsDAO;
+import gssim.db.mysql.UnitEnTimelineDAO;
+import gssim.db.mysql.UserDAO;
+
+import java.net.MalformedURLException;
+
+import javax.servlet.ServletContext;
+
+/**
+ * @author Mateusz Cichenski, Jarek Szymczak
+ */
+@BlazeDsDestination(portletEntry = false, locales = {"en_US","pl_PL"}, names = {"GSSim Studio","GSSim Studio"}, descriptions = {"Application for GSSim job description","Aplikacja do generowania zadaï¿œ dla symulatora GSSim"})
+public class ExperimentComparisonChart {
+
+	/**
+	 * The location of database source
+	 */
+	private String dbAddress = "seagrass.man.poznan.pl:3306/gssim_results";
+	/**
+	 * Username to access database
+	 */
+	private String dbUser = "gssim";
+	/**
+	 * Password to database [is it safe?]
+	 */
+	private String dbPassword = "Ua7Ahs9r";
+	
+	private Boolean developement = true;
+
+	private static MySQLDAOFactory factory;
+
+	/**
+	 * Logger instance for this class
+	 */
+    private ServiceLog log = ServiceLog.getInstance(ExperimentComparisonChart.class);
+
+	@BlazeDsMethod()
+	public ExperimentComparisonChartModel getComparisonFromDb(List experiments, List parameters) {
+
+		ExperimentComparisonChartModel model = (ExperimentComparisonChartModel) VineFlexUtilClass.getUIModel();
+		
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExperimentStatsDAO experimentStatsDAO = factory.createExperimentStats();
+			ExperimentDAO experimentDAO = factory.createExperiment();
+			
+			ArrayList<HashMap> data = new ArrayList<HashMap>();
+			for (int i = 0; i < experiments.size(); i++)
+			{
+				HashMap entry = new HashMap();
+				data.add(entry);
+				entry.put("experiment", experiments.get(i));
+				for (int j = 0; j < parameters.size(); j++)
+				{
+					ExperimentStats stat = new ExperimentStats();
+					stat.setId((Integer)experiments.get(i));
+					stat.setName((String)parameters.get(j));
+					stat = experimentStatsDAO.select(stat);
+					if (stat != null)
+						entry.put((String)parameters.get(j), stat.getValue());
+				}
+				
+				//label provider
+				Experiment exp = new Experiment();
+				exp.setPK((Integer)experiments.get(i));
+				exp = experimentDAO.select(exp);
+				entry.put("label", exp.getName());
+			}
+			model.setDataList(data);
+			
+		} catch (SQLException e) {
+			setSqlError("Resources", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	@BlazeDsMethod()
+	public ExperimentComparisonChartModel getCategoryComparisonFromDb(List experiments, List parameters) {
+
+		ExperimentComparisonChartModel model = (ExperimentComparisonChartModel) VineFlexUtilClass.getUIModel();
+		
+		Connection connection = null;
+		try {
+			connection = factory().createDBConnection(dbAddress, dbUser,
+					dbPassword);
+			
+			ExperimentStatsDAO experimentStatsDAO = factory.createExperimentStats();
+			
+			ArrayList<HashMap> data = new ArrayList<HashMap>();
+			for (int i = 0; i < parameters.size(); i++)
+			{
+				HashMap entry = new HashMap();
+				data.add(entry);
+				entry.put("experiment", parameters.get(i));
+				for (int j = 0; j < experiments.size(); j++)
+				{
+					ExperimentStats stat = new ExperimentStats();
+					stat.setName((String)parameters.get(i));
+					stat.setId((Integer)experiments.get(j));
+					stat = experimentStatsDAO.select(stat);	
+					if (stat != null)
+						entry.put((Integer)experiments.get(j), stat.getValue());
+				}
+			}
+			
+			model.setDataList(data);
+			
+		} catch (SQLException e) {
+			setSqlError("Resources", model, e);
+		} catch (InstantiationException e) {
+			setDbConnectionError(model, e);		
+		} catch (IllegalAccessException e) {
+			setDbConnectionError(model, e);	
+		} catch (ClassNotFoundException e) {
+			setDbConnectionError(model, e);	
+		} catch (Exception e) {
+			setError("Unexpected error occured", model, e);	
+		} finally {
+			closeConnection(connection, model);
+		}
+
+		return model;
+	}
+	
+	private void closeConnection(Connection connection, ExperimentComparisonChartModel model) {
+		String error = model.getError();
+		
+		if (connection != null)
+			try {
+				connection.close();
+			} catch (SQLException e) {
+				error = model.getError();
+				if (error == null || error.equals("")) {
+					error = "Error while trying to close the SQL connection";
+				} else {
+					error += System.getProperty("line.separator");
+					error += "Error while trying to close the SQL connection";
+				}
+			}
+
+		model.setError(error);
+	}
+
+	private void setSqlError(String name, ExperimentComparisonChartModel model, Exception e) {
+		setError(name + ": an SQL exception occured while trying retrieve data from database", model, e);
+	}
+	
+	private void setDbConnectionError(ExperimentComparisonChartModel model, Exception e) {
+		setError("An exception occured while trying to create MySQLDAOFactory", model, e);
+	}
+	
+	private void setError(String messageForUser, ExperimentComparisonChartModel model, Exception e) {
+		
+		String error = messageForUser;
+		
+		if(developement)
+		{
+			error += System.getProperty("line.separator");
+			error += "Error details:";
+			error += System.getProperty("line.separator");
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			PrintStream ps = new PrintStream(baos);
+			e.printStackTrace(ps);
+			String stackTrace = baos.toString();		
+			error += stackTrace;
+		}
+		
+		model.setError(error);
+	}			
+	
+	private MySQLDAOFactory factory() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+		if(factory == null)
+			factory = new MySQLDAOFactory();
+		return factory;
+	}
+	/* END OF DB Methods */
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExperimentComparisonChartModel.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExperimentComparisonChartModel.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExperimentComparisonChartModel.java	(revision 15)
@@ -0,0 +1,59 @@
+package gssim.gssimstudio.flex.app.editor;
+
+import java.io.Serializable;
+import org.vinetoolkit.grms3client.GRMS3Job;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import gssim.db.dao.data.Allocation;
+import gssim.db.dao.data.AllocationDetails;
+import gssim.db.dao.data.BlobProperty;
+import gssim.db.dao.data.Configuration;
+import gssim.db.dao.data.Metaexperiment;
+import gssim.db.dao.data.Experiment;
+import gssim.db.dao.data.ExperimentStats;
+import gssim.db.dao.data.Queues;
+import gssim.db.dao.data.Plugin;
+import gssim.db.dao.data.Reservation;
+import gssim.db.dao.data.ReservationDetails;
+import gssim.db.dao.data.Resource;
+import gssim.db.dao.data.ResourceAllTimeline;
+import gssim.db.dao.data.ResourceEnTimeline;
+import gssim.db.dao.data.Task;
+import gssim.db.dao.data.TextProperty;
+import gssim.db.dao.data.Unit;
+import gssim.db.dao.data.UnitAllTimeline;
+import gssim.db.dao.data.UnitDetails;
+import gssim.db.dao.data.UnitEnTimeline;
+import gssim.db.dao.data.User;
+
+/*
+ * @author Mateusz Cicheï¿œski, Jarek Szymczak
+ */
+public class ExperimentComparisonChartModel implements Serializable {
+
+    //    IMPORTANT - please regenerate your serialVersionUID
+    private static final long serialVersionUID = 5436766887639900748L;
+	
+	/* FIELDS FOR DB DATA */
+	private String error;
+	private ArrayList<HashMap> dataList;
+	/* END OF DB DATA */
+
+	public String getError() {
+		return error;
+	}
+
+	public void setError(String error) {
+		this.error = error;
+	}
+	
+	public ArrayList<HashMap> getDataList() {
+		return dataList;
+	}
+
+	public void setDataList(ArrayList<HashMap> dataList) {
+		this.dataList = dataList;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudioConstants.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudioConstants.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/GSSimStudioConstants.java	(revision 15)
@@ -0,0 +1,14 @@
+package gssim.gssimstudio.flex.app.editor;
+
+import java.io.Serializable;
+
+/*
+ * @author Mateusz Cicheï¿œski, Jarek Szymczak
+ */
+public class GSSimStudioConstants implements Serializable {
+
+    //    IMPORTANT - please regenerate your serialVersionUID
+    private static final long serialVersionUID = 5436766887639900865L;
+
+	public static final String NetworkTopologyBlobProperty = "Network topology";
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExtendedConfiguration.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExtendedConfiguration.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/editor/ExtendedConfiguration.java	(revision 15)
@@ -0,0 +1,56 @@
+/*
+ * @author Mateusz CicheÅski, Jarek Szymczak
+ */
+package gssim.gssimstudio.flex.app.editor;
+
+import gssim.db.dao.data.BlobProperty;
+import gssim.db.dao.data.TextProperty;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Template provided by the Vine Toolkit project.
+ * 
+ */
+public class ExtendedConfiguration implements Serializable {
+
+	// IMPORTANT - please regenerate your serialVersionUID
+	private static final long serialVersionUID = 54367668639900902L;
+
+	private int configurationId;
+	private String networkTopology;
+	private List<BlobProperty> blobPropertyList;
+	private List<TextProperty> textPropertyList;	
+	
+	public int getConfigurationId() {
+		return configurationId;
+	}
+	
+	public void setConfigurationId(int configurationId) {
+		this.configurationId = configurationId;
+	}
+	
+	public String getNetworkTopology() {
+		return networkTopology;
+	}
+	public void setNetworkTopology(String networkTopology) {
+		this.networkTopology = networkTopology;
+	}
+	
+	public List<BlobProperty> getBlobPropertyList() {
+		return blobPropertyList;
+	}
+
+	public void setBlobPropertyList(List<BlobProperty> blobPropertyList) {
+		this.blobPropertyList = blobPropertyList;
+	}
+
+	public List<TextProperty> getTextPropertyList() {
+		return textPropertyList;
+	}
+
+	public void setTextPropertyList(List<TextProperty> textPropertyList) {
+		this.textPropertyList = textPropertyList;
+	}
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/example/Example.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/example/Example.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/example/Example.java	(revision 15)
@@ -0,0 +1,46 @@
+package gssim.gssimstudio.flex.app.example;
+
+import org.vinetoolkit.web.spi.annotation.BlazeDsDestination;
+import org.vinetoolkit.web.spi.annotation.BlazeDsMethod;
+import org.vinetoolkit.web.flex.blazeds.shared.utils.VineFlexUtilClass;
+import org.vinetoolkit.web.portlet.spi.annotation.PortletDisplayName;
+import org.vinetoolkit.role.VineRoleManager;
+import org.vinetoolkit.spi.util.ServiceLog;
+
+
+/**
+ * Template provided by the Vine Toolkit project.
+ *
+ */
+@BlazeDsDestination()
+@PortletDisplayName(locales = {"en", "pl"}, values = {"Example from gssimstudio project", "PrzykÅad z projektu gssimstudio"})
+public class Example {
+
+    private ServiceLog log = ServiceLog.getInstance(Example.class);
+
+    @BlazeDsMethod(role = VineRoleManager.vineGuestRole)
+    public ExampleModel doTestMethodPublished() {
+
+        ExampleModel exampleModel = (ExampleModel) VineFlexUtilClass.getUIModel();
+
+        log.debug("CATALINA_HOME through published method!! " + doTestMethodUnpublished());
+        exampleModel.setMessage("CATALINA_HOME through published method 111 " + doTestMethodUnpublished());
+        return exampleModel;
+
+    }
+
+    @BlazeDsMethod()
+    public ExampleModel doTestMethodPublishedLoggedIn() {
+
+        ExampleModel exampleModel = (ExampleModel) VineFlexUtilClass.getUIModel();
+
+        exampleModel.setMessageAuthenticated("CATALINA_HOME through published method logged in 111 " + doTestMethodUnpublished());
+        return exampleModel;
+
+    }
+
+    public String doTestMethodUnpublished() {
+        return System.getenv("CATALINA_HOME");
+    }
+
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/example/ExampleModel.java
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/example/ExampleModel.java	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/java/gssim/gssimstudio/flex/app/example/ExampleModel.java	(revision 15)
@@ -0,0 +1,32 @@
+package gssim.gssimstudio.flex.app.example;
+
+import java.io.Serializable;
+
+/**
+ * Template provided by the Vine Toolkit project.
+ *
+ */
+public class ExampleModel implements Serializable {
+
+    //    IMPORTANT - please regenerate your serialVersionUID
+    private static final long serialVersionUID = -5436866887635100102L;
+
+    private String message;
+    private String messageAuthenticated;
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getMessageAuthenticated() {
+        return messageAuthenticated;
+    }
+
+    public void setMessageAuthenticated(String messageAuthenticated) {
+        this.messageAuthenticated = messageAuthenticated;
+    }
+}
Index: /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/.settings/org.eclipse.core.resources.prefs
===================================================================
--- /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/.settings/org.eclipse.core.resources.prefs	(revision 15)
+++ /gssim_ui/branches/vine/gssimstudio/src/web/ui/flex/.settings/org.eclipse.core.resources.prefs	(revision 15)
@@ -0,0 +1,10 @@
+#Tue Jul 05 12:19:45 CEST 2011
+eclipse.preferences.version=1
+encoding//locale/en_US/ExperimentEditor.properties=UTF-8
+encoding//locale/pl_PL/ArchiveViewer.properties=UTF-8
+encoding//locale/pl_PL/Common.properties=UTF-8
+encoding//locale/pl_PL/ExperimentEditor.properties=UTF-8
+encoding//locale/pl_PL/ResourceEditor.properties=UTF-8
+encoding//locale/pl_PL/TopologyEditor.properties=UTF-8
+encoding//locale/pl_PL/WorkloadEditor.properties=UTF-8
+encoding/<project>=utf-8
Index: /gssim_ui/branches/vine/dodanie_nowego_projektu_do_liferaya.txt
===================================================================
--- /gssim_ui/branches/vine/dodanie_nowego_projektu_do_liferaya.txt	(revision 15)
+++ /gssim_ui/branches/vine/dodanie_nowego_projektu_do_liferaya.txt	(revision 15)
@@ -0,0 +1,21 @@
+Wymagania:
+Rozpakowany vine (np na C:/)
+Rozpakowany liferay (np na C:/)
+
+Z poziomu folderu VINE TOOLKIT:
+- wywo³aæ z linii poleceñ: ant gui
+- dodaæ nowy projekt:
+	Name: gssimstudio
+	Title: GSSIM Studio
+	Description: This is GSSIM Studio portlet app.
+	Package prefix: gssim
+	Main source tree: yes
+	Web source tree: yes
+	Flex support: yes
+	Suppoerted locale: pl_PL
+- wybraæ "Save changes"
+- w zak³adce installers wybraæ u¿yty instalator VINE TOOLKIT i dodaæ nowo utworzony projekt (klikniêcie z przytrzymanym control [ctrl]), do tego instalatora
+
+- przekopiowaæ aktualny kod z gssimstudio (repozytorium gssim) do nowo-utworzonego folderu z projektem
+
+- wywo³aæ z linii poleceñ: ant install
